OVERを使用したウィンドウ関数でのDISTINCTの使用


18

OracleからSQL Server 2014にクエリを移行しようとしています。

Oracleでうまく機能するクエリを次に示します。

select
count(distinct A) over (partition by B) / count(*) over() as A_B
from MyTable 

これは、SQL Server 2014でこのクエリを実行しようとした後に取得したエラーです。

Use of DISTINCT is not allowed with the OVER clause

誰が問題を知っていますか?SQL Serverではこのような種類のクエリが可能ですか?お知らせ下さい。


あなたは実際にすべての行の結果に1行が必要MyTableですか?または、個別の行で十分ですか?また行がない場合、ゼロによる除算エラーを考慮する必要はありませんMyTableか?
アーウィンブランドステッター

回答:


12

誰が問題を知っていますか?SQL Serverではこのような種類のクエリが可能ですか?

いいえ、現在実装されていません。次の接続アイテムリクエストを参照してください。

OVER句の拡張要求-集約関数のDISTINCT句

別の可能なバリアントは

SELECT M.A,
       M.B,
       T.A_B
FROM   MyTable M
       JOIN (SELECT CAST(COUNT(DISTINCT A) AS NUMERIC(18,8)) / SUM(COUNT(*)) OVER() AS A_B,
                    B
             FROM   MyTable
             GROUP  BY B) T
         ON EXISTS (SELECT M.B INTERSECT SELECT T.B) 

NUMERIC整数の除算を避けるために、そこへのキャストがあります。ここでは、結合句の理由について説明します

ON M.B = T.B OR (M.B IS NULL AND T.B IS NULL)必要にON M.B = T.B応じて(または単にB列がNULL可能でない場合)に置き換えることができます。


14

これにより、Bで分割されたAの個別のcount(*)が得られます。

dense_rank() over (partition by B order by A) 
+ dense_rank() over (partition by B order by A desc) 
- 1

3
興味深いソリューション。Anull不可の場合にのみ機能するという免責事項が必要だと思います(nullもカウントすると思います)。
ypercubeᵀᴹ

abs(dense_rank - dense_rank) + 1私は信じるべきです。
norcalli

7

の最大値dense_rank()を取得して、Bで分割されたAの個別のカウントを取得できます。

AがNULL値を持つ可能性があるケースを処理するfirst_valueために、パーティションにNULLが存在するかどうかを判断し、コメントでMartin Smithによって示唆されている場合は1を引きます。

select (max(T.DenseRankA) over(partition by T.B) - 
          cast(iif(T.FirstA is null, 1, 0) as numeric(18, 8))) / T.TotalCount as A_B
from (
     select dense_rank() over(partition by T.B order by T.A) DenseRankA,
            first_value(T.A) over(partition by T.B order by T.A) as FirstA,
            count(*) over() as TotalCount,
            T.A,
            T.B
     from MyTable as T
     ) as T

5

サブクエリを実行し、A、Bでグループ化し、カウントを含めてみてください。次に、外部クエリで、count(distinct)が通常のカウントになり、count(*)がsum(cnt)になります。

select
count(A) over (partition by B) * 1.0 / 
    sum(cnt) over() as A_B
from
(select A, B, count(*) as cnt
 from MyTable
 group by A, B) as partial;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.