从某种意义上说,这是对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
;
计算的核心部分是这个(我首先要指出的是,这个想法不是我的,我从其他地方学到了这个技巧):
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
如果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
;
此现场演示在分贝<> fiddle.uk可用于测试溶液的两个变型。