在聚合函数SQL Server中选择N行

时间:2017-11-28 14:16:54

标签: sql sql-server window-functions partition

我有一个看起来像这样的表:

+--------+----------+--------+------------+-------+
|   ID   | CHANNEL  | VENDOR | num_PERIOD | SALES |
+--------+----------+--------+------------+-------+
| 000001 | Business | Shop   |          1 | 40    |
| 000001 | Business | Shop   |          2 | 60    |
| 000001 | Business | Shop   |          3 | NULL  |
+--------+----------+--------+------------+-------+

随着时间的推移,每个IDCHANNELVENDOR以及sales记录的组合很多(num_PERIOD)。

我们的想法是获取一个新列,该列返回SALES列中的NULLS数,但是根据num_PERIOD列返回前111个寄存器。

我一直在尝试这样的事情:

SELECT ID,
       CHANNEL,
       VENDOR,
       sum(CASE
               WHEN SALES IS NULL THEN 1
               ELSE 0
           END) OVER (PARTITION BY ID,
                                   CHANNEL,
                                   VENDOR
                      ORDER BY num_PERIOD ROWS BETWEEN UNBOUNDED PRECEDING AND 111 FOLLOWING) AS NULL_SALES_SET
FROM TABLE
GROUP BY ID,
         CHANNEL,
         VENDOR

但我没有得到我想要的东西。

所以要获得一个表格simillar:

+--------+--------------+--------+----------------+
|   ID   |   CHANNEL    | VENDOR | NULL_SALES_SET |
+--------+--------------+--------+----------------+
| 000001 | Business     | Shop   |              1 |
| 000002 | Business     | Market |              0 |
| 000002 | Non Business | Shop   |              3 |
+--------+--------------+--------+----------------+

ID排序的CHANNELVENDORnum_PERIOD排序前111行时遇到困难。

2 个答案:

答案 0 :(得分:2)

使用带有ROW_NUMBER窗口函数的CTE(公用表表达式),您应该设置:

;WITH MyCTE AS
(
    SELECT
        id,
        channel,
        vendor,
        sales,
        ROW_NUMBER() OVER (PARTITION BY id, channel, vendor ORDER BY num_period) AS row_num
    FROM
        MyTable
)
SELECT
    id,
    channel,
    vendor,
    SUM(CASE WHEN sales IS NULL THEN 1 ELSE 0 END) AS null_sales_set
FROM
    MyCTE
WHERE
    row_num <= 111
GROUP BY
    id, channel, vendor

答案 1 :(得分:1)

你必须使用窗口函数吗?

SELECT ID
     , CHANNEL
     , VENDOR
     , NULL_SALES_SET = SUM(CASE WHEN SALES IS NULL THEN 1 ELSE 0 END)
  FROM Table
 WHERE num_PERIOD <= 111
 GROUP BY ID, CHANNEL, VENDOR

或者您是否正在寻找允许num_PERIOD列中出现空白的前111个num_PERIOD值?

SELECT t.ID
     , t.CHANNEL
     , t.VENDOR
     , NULL_SALES_SET = SUM(CASE WHEN t.SALES IS NULL THEN 1 ELSE 0 END)
  FROM Table t
        INNER JOIN ( SELECT i.ID
                          , i.CHANNEL
                          , i.VENDOR
                          , i.num_PERIOD
                          , rowNum = ROW_NUMBER(PARTITION BY i.ID, i.CHANNEL, i.VENDOR ORDER BY i.num_PERIOD)
                       FROM Table i ) l
          ON t.ID = l.ID
         AND t.CHANNEL = l.CHANNEL
         AND t.VENDOR = l.VENDOR
         AND t.num_PERIOD = l.num_PERIOD
 WHERE l.rowNum <= 111
 GROUP BY ID, CHANNEL, VENDOR

编辑:不确定我是如何忽略它的,但是有必要在num_PERIOD列上加入。

编辑:在不影响NULL_SALES_SET的情况下,为每个ID,渠道,供应商添加不同num_PERIOD的数量

SELECT t.ID
     , t.CHANNEL
     , t.VENDOR
       -- Counts the NULL Sales when the num_PERIOD is in the 
       -- first 111 num_PERIODs
     , NULL_SALES_SET = SUM(CASE WHEN l.rowNum IS NOT NULL AND t.SALES IS NULL 
                                   THEN 1 
                                 ELSE 0 END)
       -- Counts the distinct num_PERIOD values
     , PERIOD_COUNT = COUNT(DISTINCT t.num_PERIOD)
  FROM Table t
        LEFT OUTER JOIN ( SELECT i.ID
                               , i.CHANNEL
                               , i.VENDOR
                               , i.num_PERIOD
                               , rowNum = ROW_NUMBER(PARTITION BY i.ID,
                                                                  i.CHANNEL,
                                                                  i.VENDOR
                                                     ORDER BY i.num_PERIOD)
                          FROM Table i ) l
          ON t.ID = l.ID
         AND t.CHANNEL = l.CHANNEL
         AND t.VENDOR = l.VENDOR
         AND t.num_PERIOD = l.num_PERIOD
         AND l.rowNum <= 111
 GROUP BY ID, CHANNEL, VENDOR