Previous | Table of Contents | Next |
The CASE expression has five keywords associated with it: the CASE keyword starts it all off; WHEN presents the boolean expression tests; THEN precedes the expression return value that the CASE expression represents for a particular row; ELSE gives an expression that is returned when none of the WHEN tests are true; and the END keyword marks the end of the CASE expression.
If you want to know more, look at the last day for some ultra-neato uses for CASE, such as a conditional view. (If its Friday, show them these rows; on Saturday, show them these rows ). Now, however, Ill present a topic that shows up in the newsgroups about once every month or two: how to write a crosstab report.
A crosstab report is a report that draws information from a table, then lists that information with one of the columns down the side, as usual, and another column across the top. This is harder than it sounds, because you are turning row information into column information.
Heres an example: New Moon Books, a publisher in the publishers table, wants a report of books that they have published. This report should list each of their titles, and the amount sold, by year.
It is a simple matter to get the data for total books sold for this publisher:
select s.title_id, sum(s.qty) from titles t, sales s, publishers p where p.pub_id = t.pub_id and t.title_id = s.title_id and p.pub_name = New Moon Books
title_id -------- ---------- BU2075 35 PS2091 108 PS2106 25 PS3333 15 PS7777 25 (5 row(s) affected)
This query gives a report of each of the publishers titles, together with the total amount sold. But the sales table contains data for the years 1992, 1993, and 1994. The publisher requested information itemized by year. For that, you need to create a crosstab report.
OK, lets try this again. To create the information by year, I need to have four columns: one column to hold the title_id, and one column each for the years 1992, 1993, and 1994. Ill use the CASE expression in each column to provide the quantity sold for that year only.
Heres the query:
select s.title_id, sum(case datepart(yy, s.ord_date) when 1992 then s.qty else 0 end ) 1992, sum(case datepart(yy, s.ord_date) when 1993 then s.qty else 0 end ) 1993, sum(case datepart(yy, s.ord_date) when 1994 then s.qty else 0 end ) 1994 from sales s, publishers p, titles t where s.title_id = t.title_id and t.pub_id = p.pub_id and p.pub_name = New Moon Books group by s.title_id
title_id 1992 1993 1994 -------- -------- ------ --------- BU2075 0 35 0 PS2091 0 0 108 PS2106 0 25 0 PS3333 0 15 0 PS7777 0 25 0 (5 row(s) affected)
Dont let the voluminous nature of this query scare you. Let me break it down
The join information is the same as the previous query: I need to get the publishers name from publishers and restrict the titles I will include from the sales table, based on the join between publishers and titles, then titles to sales. The information I really want is in the sales table. The join culls the rows in sales down to titles published by New Moon Books.
When the CASE statement runs, it evaluates each row in sales separately. The rows that match the WHERE condition are each evaluated. Here are the rows from sales that pass the WHERE test:
select s.title_id, s.qty from titles t, sales s, publishers p where p.pub_id = t.pub_id and t.title_id = s.title_id and p.pub_name = New Moon Books
title_id qty ord_date ------- ------ -------------------------- BU2075 35 Feb 21 1993 12:00AM PS2091 75 Sep 13 1994 12:00AM PS2091 10 Sep 14 1994 12:00AM PS2091 20 Sep 14 1994 12:00AM PS2091 3 Sep 13 1994 12:00AM PS2106 25 May 29 1993 12:00AM PS3333 15 May 29 1993 12:00AM PS7777 25 May 29 1993 12:00AM (8 row(s) affected)
PS2091 has four rows in the sales table, representing four different orders. It so happens that all of those orders came in 1994. No matterwhat I want is the sum of those sales for 1994.
Three CASE expressions are evaluated for each row, one each for the 1992, 1993, and 1994 columns. Lets take the 1992 column first. The CASE expression evaluates the ord_date column. If the order occurred in 1992which, youll notice, none of these sales didthen the CASE would have returned a value of qty, or 35, for the first row. Because the order did not occur in 1992, the ELSE expression is returned, which is 0. Each row is evaluated; none of them came in 1992, so the sums for each title_id for the second (1992) column are all zero.
Now the 1993 column is evaluated. Again, each row is evaluated to see if it occurred in 1993. This time, some title_ids have sales in 93. For each row that occurs in 1993, that rows quantity is added to the sum for its title_id. The same for 1994.
When the sums have been calculated, the results are grouped by title_id. The resultant report shows me exactly what I needed.
Previous | Table of Contents | Next |