これは、ある意味、レナートのソリューションの拡張ですが、あまりにも醜いので、編集として提案するつもりはありません。ここでの目標は、派生テーブルなしで結果を取得することです。それが必要になることは決してなく、クエリの醜さと相まって、全体の努力は無駄な努力のように思えるかもしれません。私はまだこれを演習として行いたいと思っていましたが、今私の結果を共有したいと思います:
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
nullが含まれないことが保証されている場合は、この式をそのまま使用できます。ただし、列にnullが含まれる可能性がある場合は、それを考慮する必要があり、それがまさにCASE
式の目的です。パーティションごとの行数とパーティションごとのCol_B
値の数を比較します。数値が異なる場合は、一部の行にnullが含まれている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
;
db <> fiddle.ukにあるこのライブデモを使用して、ソリューションの両方のバリエーションをテストできます。