sar*_*a92 11 sql-server count window-functions
我有一个包含两列的表,我想计算 Col_B 上(由)Col_A 上的不同值。
我的表
Col_A | Col_B
A | 1
A | 1
A | 2
A | 2
A | 2
A | 3
b | 4
b | 4
b | 5
Run Code Online (Sandbox Code Playgroud)
预期结果
Col_A | Col_B | Result
A | 1 | 3
A | 1 | 3
A | 2 | 3
A | 2 | 3
A | 2 | 3
A | 3 | 3
b | 4 | 2
b | 4 | 2
b | 5 | 2
Run Code Online (Sandbox Code Playgroud)
我尝试了以下代码
select *,
count (distinct col_B) over (partition by col_A) as 'Result'
from MyTable
Run Code Online (Sandbox Code Playgroud)
计数(不同的 col_B)不起作用。如何重写计数函数来计算不同的值?
Eri*_*ing 19
这就是我要做的:
SELECT *
FROM #MyTable AS mt
CROSS APPLY ( SELECT COUNT(DISTINCT mt2.Col_B) AS dc
FROM #MyTable AS mt2
WHERE mt2.Col_A = mt.Col_A
-- GROUP BY mt2.Col_A
) AS ca;
Run Code Online (Sandbox Code Playgroud)
GROUP BY
鉴于问题中提供的数据,该子句是多余的,但可能会为您提供更好的执行计划。见后续问答CROSS APPLY 产生外连接。
如果您希望将该功能添加到 SQL Server,请考虑投票支持OVER 子句增强请求 -反馈站点上聚合函数的 DISTINCT 子句。
在某种程度上,这是Lennart 解决方案的扩展,但它太丑了,我不敢建议将其作为编辑。这里的目标是在没有派生表的情况下获得结果。可能永远不需要这样做,再加上查询的丑陋,整个努力似乎是一种浪费。不过,我仍然想将此作为练习,现在想分享我的结果:
SELECT
Col_A,
Col_B,
DistinctCount = DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
+ DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
- 1
- CASE COUNT(Col_B) OVER (PARTITION BY Col_A)
WHEN COUNT( * ) OVER (PARTITION BY Col_A)
THEN 0
ELSE 1
END
FROM
dbo.MyTable
;
Run Code Online (Sandbox Code Playgroud)
计算的核心部分是这样的(我首先要注意这个想法不是我的,我在别处学到了这个技巧):
DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
+ DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
- 1
Run Code Online (Sandbox Code Playgroud)
如果Col_B
保证中的值永远不会有空值,则可以不加任何更改地使用此表达式。但是,如果该列可以有空值,则您需要考虑到这一点,而这正是CASE
表达式的用途。它将每个分区的行数与每个分区的Col_B
值数进行比较。如果数字不同,则意味着某些行中有空值Col_B
,因此DENSE_RANK() ... + DENSE_RANK() - 1
需要将初始计算 ( ) 减 1。
请注意,因为- 1
是核心公式的一部分,所以我选择保留它。但是,它实际上可以合并到CASE
表达式中,以徒劳的尝试使整个解决方案看起来不那么难看:
SELECT
Col_A,
Col_B,
DistinctCount = DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B ASC )
+ DENSE_RANK() OVER (PARTITION BY Col_A ORDER BY Col_B DESC)
- CASE COUNT(Col_B) OVER (PARTITION BY Col_A)
WHEN COUNT( * ) OVER (PARTITION BY Col_A)
THEN 1
ELSE 2
END
FROM
dbo.MyTable
;
Run Code Online (Sandbox Code Playgroud)
这个现场演示在db<>fiddle.uk 可用于测试解决方案的两种变体。
您可以使用 模拟它dense_rank
,然后为每个分区选择最大等级:
select col_a, col_b, max(rnk) over (partition by col_a)
from (
select col_a, col_b
, dense_rank() over (partition by col_A order by col_b) as rnk
from #mytable
) as t
Run Code Online (Sandbox Code Playgroud)
您需要从 中排除任何空值col_b
以获得与COUNT(DISTINCT)
.
归档时间: |
|
查看次数: |
15951 次 |
最近记录: |