views:

1271

answers:

3

**Update:

using the Rank() over partition syntax available in MS SQL Server 2005 does indeed point me in the right direction, it (or maybe I should write "I") is unable to give me the results I need without resorting to enumerating rows in code.

For example, if we select TOP (1) of rank, I get only one value, ie., slot 1. If I use MAX(), then I get the top ranked value for each slot...which, in my case, doesn't work, because if slot 2's top value is NULL, but it's next to MAX value is non-empty, that is the one I want.

So, unable to find a completely T-SQL solution, I've resorted to filtering as much as possible in SQL and then enumerating the results in code on the client side.

Original:

I've been hitting advanced T-SQL books, StackOverflow and google trying to figure out how to handle this query either by using pivots or by using analytic functions. So far, I haven't hit on the right combination.

I have schedules that are ranked (higher value, greater precedence). Each schedule has a playlist of a certain number of numbered slots with files.

What I need to do, is line up all the schedules and their associated playlists, and for each slot, grab the file from the schedule having the highest ranking value.

so, if I had a query for a specific customer with a join between the playlists and the schedules, ordered by Schedule.Rank DESC like so:

PlaylistId   Schedule.Rank    SlotNumber    FileId
100               100             1          1001
100               100             2          NULL
100               100             3          NULL
200                80             1          1101
200                80             2          NULL 
200                80             3          NULL
300                60             1          1201
300                60             2          NULL
300                60             3          2202
400                20             1          1301
400                20             2          2301
400                20             3          NULL

From this, I need to find the FileId for the MAX ranked row per slotnumber:

SlotNumber   FileId    Schedule.Rank
1             1001         100
2             2301          20
3             2202          60

Any ideas on how to do this?

Table Definitions below:

CREATE TABLE dbo.Playlists(
    id int NOT NULL)

CREATE TABLE dbo.Customers(
    id int NOT NULL,
    name nchar(10) NULL)

CREATE TABLE dbo.Schedules(
    id int NOT NULL,
    rank int NOT NULL,
    playlistid int NULL,
    customerid int NULL)

CREATE TABLE dbo.PlaylistSlots(
    id int NOT NULL,
    slotnumber int NOT NULL,
    playlistid int NULL,
    fileid int NULL)
+1  A: 

Have you looked at SQL Server's (2005 onwards) PARTITION and RANK features?

Mitch Wheat
I have read about those on SO and the MSDN docs....but haven't been able to use them successfully at this point.
Todd Brooks
They are ideal for the problem you've stated.
Mitch Wheat
Yep - I was busy typing the concise code for a partition-based solution even as your answer arrived, @Mitch (hope it's right, no time to test, sorry). So, as a general SO issue, what's best - teach Todd to fish as you're doing, or trying to give him a fish as I'm doing? Not a rhetorical question, I'm pretty new here and trying to learn SO's style by seeing what old-timers do, but it seems both approaches are quite popular - tx for any feedback!
Alex Martelli
@Alex, your answer points me in the right direction. Many thanks. My post on SO was very simplistic for brevity, so while your answer may be correct for the simplistic example, I at least have a direction for finishing the solution.
Todd Brooks
@Todd, your SO question was _perfect_ -- highlighting all the aspects one needed to give a response, AND omitting irrelevancies; Eric Raymond would be proud of you. @Mitch's answer is also excellent, and the URL he points to is *very* useful too.
Alex Martelli
+3  A: 
SELECT slotnumber, fileid, rank
FROM Schedules
INNER JOIN PlaylistSlots
  ON Schedules.playlistid = PlaylistSlots.playlistid
WHERE
 RANK() OVER (PARTITION BY slotnumber ORDER BY rank DESC) = 1
Alex Martelli
while this answer isn't exactly correct (the windowed function in the criteria throws an error), the roots of this answer led me to my implementation-specific answer.
Todd Brooks
so can you please post the exactly-correct version (or tell me how to edit mine)? as I mentioned in a comment to @mitch's answer I couldn't test this, so some (hopefully minor!-) error can well have crept in -- thanks!
Alex Martelli
still working on solution, but in order to fix the windowed function issue, you can wrap the entire select in a derived table. I'm still not getting the results I need, but I'm heading in the right direction. When I have a working solution, I'll edit the original question with the full answer.
Todd Brooks
A: 

select SlotNumber, FileId, ScheduleRank
FROM intermediateTable a, 
(
   SELECT SlotNumber, Max(Schedule.Rank) as MaxRank
   FROM intermediateTable O
   WHERE FileId is not null GROUP BY SlotNumber) b
WHERE b.SlotNumber = a.SlotNumber and b.MaxRank = a.Rank

This query uses the intermediate output to build the final output.
Does this help?

shahkalpesh
IMHO it's indeed important to also show approaches that are portable to other SQL engines w/o rank and partition features, as yours would be, but I don't see where the intermediateTable is formed or how: can you pls edit yr answer for completeness? tx!
Alex Martelli
The intermediate table is the table 1 given by OP
shahkalpesh