简体   繁体   English

SQL生成一个包含多个前X个记录的表,其中top#来自另一个表

[英]SQL Generate a table of multiple top X records, where top # comes from another table

I'm using SQL Server 2012. 我正在使用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. 我的第一个表格,称为Table1,是参考表格,其中NUMBER告诉我每个独特的市场/度量需要从另一个表格中返回多少顶行。

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. 第二个表Table2列出了给定MARKET / MEASURE中每个人的详细信息,其中MARKET和MEASURE的组合是我的主要关键。 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. 对于Table1中的每个值,我需要根据一种LASTNAME以升序返回表2中的那么多顶行。 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. 因此,例如,因为Table1对于MarketA / MeasureA的NUMBER为411,我的输出需要包含Table2中的TOP 411 *行(基于该市场中按LASTNAME升序排序的所有人),以及MarketA /的TOP 396行MeasureB,然后是MarketB / MeasureA的TOP 548行,依此类推,全部在一个表中,好像我已经单独“UNIONed”(?)每个查询。

How do I do this dynamically without having to UNION individual queries for each MARKET/MEASURE in Table1 (of which there are over 1000)? 如何动态执行此操作而不必对表1中的每个MARKET / MEASURE进行UNION个别查询(其中超过1000个)?

I feel like the answer is to use a select expression to generate # in the TOP expression, like..... 我觉得答案是使用select表达式在TOP表达式中生成#,就像......

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. ...但显然我错过了几个步骤,因为TOP表达式将从TABLE2中带回多个值,而我无法弄清楚如何让它为每个MARKET / MEASURE组合“运行”。

Help much appreciated. 非常感谢。

This is what APPLY can be used for 这就是APPLY可以用来做的事情

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 http://sqlfiddle.com/#!6/46b57/4

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. 对于处于同样困境的任何人,我想出了另一种完成同样事情的方法,使用ROW_NUMBER()窗口函数而不是尝试动态使用TOP。 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. 想法是向Table2添加一个行号,按市场和度量分区并按姓氏排序,然后将Table1.Number加入Table2,并仅选择行号小于Table1.Number的行,从而返回根据Table1.Number的“top”行数。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM