【问题标题】:PARTITION BY to consider only two specific columns for aggregation?PARTITION BY 只考虑两个特定列进行聚合?
【发布时间】:2021-09-15 20:08:41
【问题描述】:

我的表有以下数据:

REF_NO PRD_GRP ACC_NO
ABC 12 1234
ABC 9C 1234
DEF AB 7890
DEF TY 9891

我正在尝试构建一个查询来汇总每个客户的帐户数量 - 产品组与此目的无关,因此我的预期结果是:

REF_NO PRD_GRP ACC_NO NO_OF_ACC
ABC 12 1234 1
ABC 9C 1234 1
DEF AB 7890 2
DEF TY 9891 2

我尝试使用窗口函数进行此操作:

SELECT
    T.REF_NO,
    T.PRD_GRP,
    T.ACC_NO,
    COUNT(T.ACC_NO) OVER (PARTITION BY T.REF_NO) AS NUM_OF_ACC

FROM TABLE T

但是,对于第一个客户 (ABC),返回的 NUM_OF_ACC 值是 2 而不是 1。该查询似乎只是计算每个客户的唯一行数,而不是根据需要确定帐户数。

我该如何解决这个错误?

链接到小提琴 - https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=83344cbe95fb46d4a1640caf0bb6d0b2

【问题讨论】:

  • 不起作用。在这种情况下,它为所有客户引用返回 1,而不仅仅是上面示例中的那个 - 我希望它计算唯一帐号的数量并返回计数,而不考虑 PRD_GRP 值。
  • 我添加了更多示例数据;道歉不是更清楚。不幸的是,实际数据在另一台笔记本电脑上,所以我无法根据需要添加 DDL+DML;(但我希望上述编辑有所帮助。
  • 是的,我有。运气不好,因为它只是为每一行返回 1。
  • 我正在尝试设置 DBFiddle...
  • @DaleK- 我添加了一个小提琴并将链接插入到我的问题中。如果你能看看就好了。谢谢!

标签: sql sql-server tsql aggregate-functions window-functions


【解决方案1】:

您需要COUNT(DISTINCT,遗憾的是SQL Server 不支持将其作为窗口函数。

但是你可以用DENSE_RANKMAX模拟它

SELECT
    T.REF_NO,
    T.PRD_GRP,
    T.ACC_NO,
    MAX(T.rn) OVER (PARTITION BY T.REF_NO) AS NUM_OF_ACC
FROM (
    SELECT *,
        DENSE_RANK() OVER (PARTITION BY T.REF_NO ORDER BY T.ACC_NO) AS rn
    FROM [TABLE] T
) T;

DENSE_RANK 将计算由ACC_NO 排序的行,但忽略平局,因此其中的MAX 将是不同值的数量。

db<>fiddle.uk

【讨论】:

    【解决方案2】:

    您需要的是COUNT(DISTINCT T.ACC_NO),不幸的是,窗口函数不支持它。因此,您必须编写一个子查询以允许您在没有窗口函数的情况下使用COUNT(DISTINCT T.ACC_NO)

    SELECT
        T.REF_NO,
        T.PRD_GRP,
        T.ACC_NO,
        -- Use of DISTINCT is not allowed with the OVER clause.
        -- COUNT(DISTINCT T.ACC_NO) OVER (PARTITION BY T.REF_NO) AS NUM_OF_ACC,
        (
            SELECT COUNT(DISTINCT T1.ACC_NO)
            FROM TEST_DATA T1
            WHERE T1.REF_NO = T.REF_NO
        ) AS NUM_OF_ACC
    FROM TEST_DATA T
    

    【讨论】:

    • 你没有使用自连接,它仍然可以只使用窗口函数.....
    • 谢谢戴尔!在这种情况下,self join 的问题是我从链接服务器中拉取数据,因此与上述 Charlie 的解决方案相比,性能要慢。
    【解决方案3】:

    count(distinct) 实现为窗口函数的最简单方法是将两个dense_ranks() 相加:

    SELECT T.REF_NO, T.PRD_GRP, T.ACC_NO,
           (-1 +
             DENSE_RANK() OVER (PARTITION BY t.REF_NO ORDER BY T.ACC_NO ASC) +
             DENSE_RANK() OVER (PARTITION BY t.REF_NO ORDER BY T.ACC_NO DESC)
            ) as cnt_distinct
    FROM TABLE T
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-22
      • 2017-01-17
      • 1970-01-01
      • 2020-12-27
      相关资源
      最近更新 更多