Reputation: 749
I'm using SQL Server 2012.
I need to generate an output that includes the results for multiple "top" queries, where the # of "top" rows returned in each query varies based on the value in another table.
My first table, call it Table1, is the reference table where NUMBER tells me how many top rows I need to return from another table for each unique MARKET/MEASURE.
MARKET MEASURE NUMBER
------ ------- ------
MarketA MeasureA 411
MarketA MeasureB 396
MarketB MeasureA 548
MarketB MeasureC 424
MarketC MeasureC 411
The second table, Table2, lists detail for each individual person in a given MARKET/MEASURE, where the combination of MARKET and MEASURE is my primary key. There are many entries for any given MARKET/MEASURE.
MARKET MEASURE LASTNAME COMPLIANT
------ ------- -------- ---------
MarketA MeasureA Coppola Y
MarketA MeasureA Winterbottom N
MarketA MeasureB Scorsese Y
MarketC MeasureC Tarr Y
For each value in Table1, I need to return that many top rows from Table2 based on a sort of LASTNAME in ascending order. So for example, because Table1 has a NUMBER of 411 for MarketA/MeasureA, my output needs to contain the TOP 411 * rows from Table2 (based on all persons in that market sorted by LASTNAME ascending), and the TOP 396 rows for MarketA/MeasureB, and then the TOP 548 rows for MarketB/MeasureA, and so on, all in one table, as if I've "UNIONed" (?) each query individually.
How do I do this dynamically without having to UNION individual queries for each MARKET/MEASURE in Table1 (of which there are over 1000)?
I feel like the answer is to use a select expression to generate # in the TOP expression, like.....
select TOP (select NUMBER from TABLE2) *
from TABLE1 t1
inner join TABLE2 t2 on t2.MARKET = T1.MARKET
and t2.MEASURE = T2.MEASURE
...but obviously I'm missing a few steps because the TOP expression will bring back multiple values from TABLE2, and I can't quite figure out how to get it to "run" for each MARKET/MEASURE combination.
Help much appreciated.
Upvotes: 1
Views: 69
Reputation: 749
For anyone in the same predicament, I figured out another way of accomplishing the same thing, using the ROW_NUMBER() windowed function instead of trying to use TOP dynamically. The idea was to add a row number to Table2, partitioned by market & measure and ordered by last name, then to join the Table1.Number to Table2, and select only rows where the row number was less than Table1.Number, thus returning the "top" number of rows according to the Table1.Number.
with temp as (select 'rownum' = row_number() over(partition by t2.market, t2.measure)
order by t2.lastname)
, t2.*
, t1.number
from table2 t2
inner join table1 t1 on t1.market = t2.market
and t1.measure = t2.measure)
select *
from temp
where rownum <= number
order by market, measure, rownum
Upvotes: 1
Reputation: 2139
This is what APPLY
can be used for
SELECT
*
FROM
Table1
CROSS APPLY
(
SELECT TOP (Table1.Number)
*
FROM
Table2
WHERE
Table1.Market = Table2.Market
AND Table1.Measure = Table2.Measure
ORDER BY
LastName
) AS TopResults
http://sqlfiddle.com/#!6/46b57/4
Upvotes: 2