Enjoy Every Sandwich

Thoughts on SQL, XML, .NET and sometimes beer.

<September 2008>
SuMoTuWeThFrSa
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011


Navigation

Tools

List O'Links

Kent's Other Stuff

Subscriptions

News

Please read these
Notices and Disclamiers

Post Categories

Article Categories



What being clumsy taught me about joining matrices

Those of you who've met me probably have figured out that I'm not the most agile person ever. One time in Gym class, when they were trying to get me to play basketball, the coach said "you're the only kid I've ever known who can't pivot." I never thought this would come back to haunt me (its not like I try to play basketball), but it did recently when working with a matrix. Its not hard to imagine treating a table in SQL Server as a matrix. What is hard -- or at least is a lot of code to write -- is doing a join on matrix to some other table. Consider for example the case of an Italian resturant. They've decided to use SQL Server to manage a number of things and a couple of them are lists of dished they prepare and a table that organizes these dishes into four-course meals. The tables might be structured something like this:
create table dbo.menuItems (itemID tinyint identity(1,1) primary key,name varchar(30) not null unique,meatless bit not null)
and
create table dbo.menu(mealID tinyint identity(1,1) primary key,antipasti tinyint,primi tinyint,secondi tinyint,dolci tinyint)
After adding some data, the contents of dbo.menu look something like:
mealID antipasti primi secondi dolci
------ --------- ----- ------- -----
1      1         5     9       13
2      2         6     10      14
3      3         7     11      15
4      4         8     12      16

And that's nice, but its not very usable by a human being. What I'd really like to get is:

mealID antipasti                      primi                          secondi                        dolci
------ ------------------------------ ------------------------------ ------------------------------ ------------------------------
1      Crostini                       Ravioli Nudi di Pesce          Pastello di Pesce              Granita
2      Prosciutto e meloni            Risotto alla Milanese          Ossobuco                       Timballo di Pere
3      Carpaccio                      Stracciatella                  Saltimbocca                    Castagnaccio
4      Polenta Fritta                 Trippa alla Fiorentina         Bollito Misto                  Zabaione

But how do you do that? In SQL Server 2005, a couple of new operators make this pretty easy: UNPIVOT and PIVOT. But how and why? Let's consider our matrix could also be represented as a list of paired values:

course     itemID
---------- ------
antipasti  1
primi      5
secondi    9
dolci      13
antipasti  2
primi      6
secondi    10
dolci      14
antipasti  3
primi      7
secondi    11
dolci      15
antipasti  4
primi      8
secondi    12
dolci      16

The unpivot operator makes that's easy to do:

select u.menuID,itemID from dbo.menu m unpivot (itemID for menuID in (antipasti,primi,secondi,dolci)) as u
And it makes joining the dishes in that list back to the table of dishes (dbo.MenuItems) rather easy: select u.menuID,i.name from dbo.menu m unpivot (itemID for menuID in (antipasti,primi,secondi,dolci)) as u join dbo.menuItems i on u.itemID = i.itemID So while that's cool, we're still dealing with a pair-list, not a matrix. Now, I might be a white guy that can't jump, but I certainly can PIVOT back into the matrix.
;with menus as (select mealID,u.menuID,i.name from dbo.menu m unpivot (itemID for menuID in (antipasti,primi,secondi,dolci)) as u join dbo.menuItems i on u.itemID = i.itemID) select * from menus pivot(max(name) for menuID in ([antipasti],[primi],[secondi],[dolci])) as p
Take that, Coach!

posted on Wednesday, September 13, 2006 5:05 PM by ktegels





Powered by Dot Net Junkies, by Telligent Systems