Select 聚合函数中的 N 行 SQL 服务器

Select N rows in aggregate functions SQL Server

我有一个 table 看起来像这样:

+--------+----------+--------+------------+-------+
|   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)。

思路是获取一个新的列,其中returns个SALES列的NULLS个数,但是前111个根据num_PERIOD列注册。

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

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

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

因此要获得 table 类似于:

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

根据 IDCHANNELVENDOR 选择这些前 111 行时遇到了困难,这些行按 num_PERIOD 排序。

将 CTE(通用 Table 表达式)与 ROW_NUMBER 窗口函数一起使用,您应该设置:

;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

一定要用开窗功能吗?

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

或者您是否在寻找前 111 个 num_PERIOD 允许 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