SQL - Update Query Using Sub Queries Update Value

Goog Feed, General, SQL    Comments (4)


I like to post anything SQL that is "new" to me that perhaps I didn't know before or don't remember doing. Today was one such occasion.

I was challenged with the task of updating a table full of reading data for for our district's 3rd-5th graders. The data was comprised of a record per student per testing cycle, and was used for the purpose of tracking reading fluency. I have a second table which holds a score matrix letting me know per grade, per testing cycle what the low and high grades should be to determine if a student is above average, below average or at average.

This was something that I had to do as a "one time event" to about 7000 plus records. I decided that I could run a bunch of queries per reading cycle per grade to do this, but that seemed cheesy to me. I wanted to do it all in one fell swoop. Here is what worked for me.

UPDATE dataTable
SET dataTable.atAboveBelow =
CASE
WHEN dataTable.readingScore < (SELECT belowAvg FROM scoreMatrix where gradeLevel = dataTable.gradeLevel AND testWindow = dataTable.testWindow) THEN -1
WHEN dataTable.readingScore > (SELECT aboveAvg FROM scoreMatrix where gradeLevel = dataTable.gradeLevel AND testWindow = dataTable.testWindow) THEN 1
ELSE 0
END

SQL 101 - Counts By Location and Grade

Goog Feed, General, SQL    Comments (0)



The Desired Result

The other day at work there was a need for a report that our reporting system was having trouble putting out. So the fix was to write it ourselves. It's not too complex and for some it may be quite elementary, but here it is none-the-less.

Being that I work for a school district there was a need for a report by campus and grade level of the number of students that fell into a certain category. So for the sake of this report we want a count of all active students based on their campus and their grade level.

Below is the stripped down version of how this was accomplished.

SELECT Campus, Grade, COUNT(studentID) AS StudentCount
FROM ourStudentTable
WHERE studentStatus = 'A'
GROUP BY Campus, Grade
ORDER BY Campus

Hopefully this helps!

SQL - Using Sub Queries As Joining Tables

Goog Feed, General, SQL    Comments (2)


Today at work I faced a dilemma. I was tasked with developing a function in which a parent could be notified when their child has an absence or a tardy in one of their classes (I work for a school district). It involved touching 3 different tables including one twice. The three types of tables are as follows, an attendance details table which we'll call AttendanceDetail, a parent/student table which ties parents with students which we'll call ParentStudent, and finally a notify parent when an absence occurs table which we'll call AttendanceNotification.

So here is the short of how the process works. Daily a routine will run checking to see if a student whose parent requested a notification upon an attendance event had missed a class and/or was tardy to class. Sounds simple enough huh? Well it wasn't as easy as first thought.

My first query was as follows...

SELECT an.studentID, ps.studentFirstName, ps.studentLastName, ad.absence_date
FROM AttendanceNotification an
INNER JOIN ParentStudent ps ON ps.studentID = an.studentID
INNER JOIN AttendanceDetail ad ON ad.studentID = an.studentID
WHERE an.notify = 1 AND ps.status = 'A'

Basically this query grabs all prior absence events for a student where they are active and the parent needs to be notified of the last absence event. So we have a bunch of unwanted events here, we just need the most recent event.

Simple enough we'll just add a couple things to our query and we'll be good to go right? Not so fast. So I added a MAX() function to the absence date which would give me the most recent absence and I grouped by the studentID which would only give me one record back per student and I ended up with the following.

SELECT an.studentID, ps.studentFirstName, ps.studentLastName, MAX(ad.absence_date) AS absenceDate
FROM AttendanceNotification an
INNER JOIN ParentStudent ps ON ps.studentID = an.studentID
INNER JOIN AttendanceDetail ad ON ad.studentID = an.studentID
WHERE an.notify = 1 AND ps.status = 'A'
GROUP BY an.studentID, ps.studentFirstname, ps.studentLastname

Well, the problems began to start, I needed to be able to show the parent what the absence event detail was. Did their student have a tardy? An unexcused absence? A doctors appointment? You get the point. My first thought was to just add it into the SELECT statement for the above query, but then I had to include them in my GROUP BY clause which caused more than one record per student to be returned. I then thought about trying to wrap them in a MAX function, that didn't work, they needed an aggregate function to be included in my SELECT criteria and not in my GROUP BY, I was at a loss.

Then I got an idea, I wondered if I could JOIN on a sub query. I had never tried it before, but it worked perfectly! I thought I'd share it with you just in case you ever ran across a similar problem.

The final query does an INNER JOIN from the AttemdanceDetail table to the previous result set or sub query. Now we're able to get detailed absence info yet only the most recent record. Here is the final query.

SELECT
   a.studentID,
   a.studentFirstName,
   a.studentLastName,
   a.absenceDate,
   CASE WHEN ltrim(rtrim(adII.am_office_abs)) IS NULL THEN ltrim(rtrim(adII.am_teacher_abs)) ELSE ltrim(rtrim(adII.am_office_abs)) END AS am,
   CASE WHEN ltrim(rtrim(adII.pm_office_abs)) IS NULL THEN ltrim(rtrim(adII.pm_teacher_abs)) ELSE ltrim(rtrim(adII.pm_office_abs)) END AS pm
FROM AttendanceDetail adII
INNER JOIN
(SELECT an.studentID, ps.studentFirstName, ps.studentLastName, MAX(ad.absence_date) AS absenceDate
FROM AttendanceNotification an
INNER JOIN ParentStudent ps ON ps.studentID = an.studentID
INNER JOIN AttendanceDetail ad ON ad.studentID = an.studentID
WHERE an.notify = 1 AND ps.status = 'A'
GROUP BY an.studentID, ps.studentFirstname, ps.studentLastname) a
ON a.studentID = adII.studentID AND a.absenceDate = adII.absence_date

Perhaps there is a better way to do this, I just don't know how, but this worked so I ran with it.

CFUnited: My Recap

Goog Feed, General, ColdFusion, CFUnited 2008, SQL    Comments (0)


CFUnited 2008 was a great experience for me personally, I presented as a speaker for the first time which was a great experience and challenge, as well as learned a great deal of things that I would like to put into practice in my own development environment.

I wanted to put a quick post out there to go over some of the highlights that I was able to take away learning wise for others to see as well as a constant reminder to myself. So, what did I personally learn?

  • In his own words, Ray Camden will be using tables for layout until someone stops him... Should've come to my session Ray!
  • I want to start using CFToolTip more for my end-users benefit.
  • There is a cool Event Validator at RiaForge that Mark Drew referenced, I would like to check into that when I get the time.
  • From Hal Helms session, leave functions open for extention, closed for changes. Keeping things simple
  • Just because MVC is used, doesn't mean I'm doing OO. I can still be doing procedural code in an MVC format.
  • Get book called Design Patterns by Gang of Four
  • Find the things that are constantly changing in my applications and encapsulate them.
  • Good OO is all about abstraction.
  • Pass objects to be persisted.
  • From Chris Scott's session, keep ColdSpring simple - getBeans/setBeans
  • Increase the JVM default on the CF Server.
  • Increase the minimum memory on the CF Server.
  • Turn on trusted cache in production.
  • Cache queries used often in applications.
  • Read the CF8 performance brief.
  • Use SQL Server performance monitoring tools to profile, trace, look at execution plans and their costs, run database reports to see which queries are putting loads on the server.
  • If session is not available, reject the form submission, because it means they didn't come from your form.
  • From Joe's advanced Model-Glue session... you can use the include tags to include entire applications into your Model-Glue app.
  • Prefix event handlers.
  • Controllers should be as thin as possible.
  • Use views for common joins, filtering, etc... when dealing with larger queries.
  • Index all fields searched on in my SQL tables for fast searching and less load on the database. A good example of this is looking for pizza in the phone book, but searching every page of the book from A-Z. With indexing you don't need to search from A-Z simply jump to 'Pizza'.
  • SQL views can be about 75% faster than CF for complex queries.
  • Stored procedures can be about 90% faster than CF.
  • Use cfQueryParams for security as well as not making the SQL Server re-write execution plans everytime a query is run.
  • Be careful about how you index your tables, you could do more damage than good if it's not done right.

That was my quick recap of what I learned. Overall the venue was great, I loved the fact that the conference was in downtown DC instead of Bethesda, the hotel was awesome and close to the conference. Another great job by the CFUnited team. I hope to return in 2009.

SQL Dynamic Date Range

Goog Feed, General, ColdFusion, SQL    Comments (0)


I work for a school district here in Texas and today an issue arose. We needed to run a nightly SQL job which pulls students from our Student Information System and dumps them into some tables we use for a local application. Problem is while we have about 22,000 active students our total student table has over 55,000 records in it, some from prior years.

The initial reaction was to hard-code the school year start and end dates into the system, but then if our DBA leaves, or we forget what kind of lame hack we put in place we have problems next school year.

I had done this previously in ColdFusion, but today I decided to do a SQL version of it. It will take the current day and decides what the current school year start and end dates are based on the current day, so we're always pulling current data only no matter what year it may be.

DECLARE @startDate datetime
DECLARE @endDate datetime

SET @startDate = cast('7/1/' + cast(datePart("yyyy",getDate()) AS varchar) AS datetime)
SET @endDate = cast('6/30/' + cast(datePart("yyyy",getDate()) AS varchar) AS datetime)

SET @startDate = CASE WHEN cast(@startDate AS datetime) > getDate() THEN cast(dateAdd("yyyy",-1,@startDate) AS datetime) ELSE cast(@startDate AS datetime) END
SET @endDate = CASE WHEN cast(@endDate AS datetime) < getDate() THEN cast(dateAdd("yyyy",1,@endDate) AS datetime) ELSE cast(@endDate AS datetime) END

SELECT @startDate AS startDate, @endDate AS endDate

The end result is 7/1/2007 as the startDate and 6/30/2008 for the endDate. It works perfect for us, and I hope it works for you.

More Entries