web-dev-qa-db-ja.com

OVERを指定したウィンドウ関数でDISTINCTを使用する

クエリを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でこのようなクエリは可能ですか?お知らせ下さい。

18
Omri

誰が問題なのか知っていますか? 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)に置き換えることができます(または、B列がnullにできない場合は、単に_ON M.B = T.B_に置き換えることができます)。

12
Martin Smith

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

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

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
7
Mikael Eriksson

サブクエリを実行して、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;
5
Rob Farley

今のところSQL Serverでは、ウィンドウ関数でDistinctを使用することはできません。

しかし、ウィンドウ関数がどのように機能するか(つまり、それらがクエリの結果セットに適用されること)を思い出したら、次のように対処できます。

select B,
min(count(distinct A)) over (partition by B) / max(count(*)) over() as A_B
from MyTable
group by B
0
AcePL