根据序数和属性数据选择前n个记录

sug*_*rum 1 t-sql sql-server sql-server-2008

我有一个案例,我需要根据表中的设置和序数集只显示顶行.

下面的示例数据集显示了两个客户; 每个客户都有不同的产品.因为NumRowsToShow是"1"我只想为每个客户显示一行(基于序数的顶行).

| CustomerID | ProductID | Ordinal | NumRowsToShow |
+------------+-----------+---------+---------------+
| 1          |A          |1        |1              |
| 1          |B          |2        |1              |
| 1          |C          |3        |1              |
| 5          |D          |1        |1              |
| 5          |E          |2        |1              |
| 5          |F          |3        |1              |
Run Code Online (Sandbox Code Playgroud)

运行查询后的结果集应该是

| CustomerID | ProductID |
+------------+-----------+
| 1          |A          |
| 5          |D          |
Run Code Online (Sandbox Code Playgroud)

在同一场景中,如果NumRowsToShow对于customerID 1为1,对于CustomerID 5为2,我会看到类似的东西.

| CustomerID | ProductID | Ordinal | NumRowsToShow |
+------------+-----------+---------+---------------+
| 1          |A          |1        |1              |
| 1          |B          |2        |1              |
| 1          |C          |3        |1              |
| 5          |D          |1        |2              |
| 5          |E          |2        |2              |
| 5          |F          |3        |2              |
Run Code Online (Sandbox Code Playgroud)

运行查询后的结果集应该是

| CustomerID | ProductID |
+------------+-----------+
| 1          |A          |
| 5          |D          |
| 5          |E          |
Run Code Online (Sandbox Code Playgroud)

如何才能做到这一点?

包括实际结果集的屏幕上限,以及我正在尝试过滤的内容的亮点可能有点帮助.

Screencap http://www.harpernet.net/se/cap01.jpg

ype*_*eᵀᴹ 6

感觉就像"在考试中作弊":

SELECT CustomerID, ProductID
FROM tableX
WHERE Ordinal <= NumRowsToShow
Run Code Online (Sandbox Code Playgroud)

如果,如评论所示,Ordinal可以有10, 20, 30值而不仅仅是1, ..., n值,那么这将起作用:

SELECT t.CustomerID, t.ProductID
FROM tableX AS t
  JOIN tableX AS tt
    ON  tt.CustomerID = t.CustomerID
    AND tt.Ordinal <= t.Ordinal
GROUP BY t.CustomerID
       , t.ProductID
       , t.NumRowsToShow
HAVING COUNT(*) <= t.NumRowsToShow
Run Code Online (Sandbox Code Playgroud)

甚至更好,:

SELECT CustomerID, ProductID
FROM
  ( SELECT CustomerID, ProductID, NumRowsToShow
         , ROW_NUMBER() OVER( PARTITION BY CustomerID 
                              ORDER BY Ordinal
                            ) AS Rn
    FROM tableX
  ) AS tmp
WHERE Rn <= NumRowsToShow ;
Run Code Online (Sandbox Code Playgroud)

测试:SQL-Fiddle


您的表看起来没有标准化.该NumRowsToShow列中有重复的信息来源,并可能导致更新异常.这个:

| CustomerID | ProductID | Ordinal | NumRowsToShow |
+------------+-----------+---------+---------------+
| 1          |A          |1        |1              |
| 1          |B          |2        |1              |
| 1          |C          |3        |1              |
| 5          |D          |1        |2              |
| 5          |E          |2        |2              |
| 5          |F          |3        |2              |
Run Code Online (Sandbox Code Playgroud)

可以归一化为2个表格:

| CustomerID | ProductID | Ordinal |
+------------+-----------+---------+
| 1          |A          |1        |
| 1          |B          |2        |
| 1          |C          |3        |
| 5          |D          |1        |
| 5          |E          |2        |
| 5          |F          |3        |
Run Code Online (Sandbox Code Playgroud)

和:

| CustomerID | NumRowsToShow |
+------------+---------------+
| 1          |1              |
| 5          |2              |
Run Code Online (Sandbox Code Playgroud)