私は次のように書いて、個別のNumUsersの合計を取得しようとしています:
NumUsers = COUNT(DISTINCT [UserAccountKey]) OVER (PARTITION BY [Mth])
管理スタジオはこれについてあまり満足していないようです。 DISTINCT
キーワードを削除するとエラーは表示されなくなりますが、明確なカウントにはなりません。
DISTINCT
は、パーティション関数内では使用できないようです。個別のカウントを見つけるにはどうすればよいですか?相関サブクエリなど、より多くのtraditionalメソッドを使用しますか?
これをもう少し検討すると、これらのOVER
関数は、SQL-Server
で使用して合計を計算できないという点で、Oracleとは異なる動作をする可能性があります。
ここに SQLfiddle にライブ例を追加しました。ここでは、パーティション関数を使用して実行中の合計を計算しようとしています。
dense_rank()
を使用した非常に簡単なソリューションがあります
dense_rank() over (partition by [Mth] order by [UserAccountKey])
+ dense_rank() over (partition by [Mth] order by [UserAccountKey] desc)
- 1
これにより、まさにあなたが求めていたものが得られます。各月内の個別のUserAccountKeysの数。
SQL-Server 2008R2でこれを行う唯一の方法は、相関サブクエリまたは外部適用を使用することだと思います。
SELECT datekey,
COALESCE(RunningTotal, 0) AS RunningTotal,
COALESCE(RunningCount, 0) AS RunningCount,
COALESCE(RunningDistinctCount, 0) AS RunningDistinctCount
FROM document
OUTER APPLY
( SELECT SUM(Amount) AS RunningTotal,
COUNT(1) AS RunningCount,
COUNT(DISTINCT d2.dateKey) AS RunningDistinctCount
FROM Document d2
WHERE d2.DateKey <= document.DateKey
) rt;
これは、提案した構文を使用して SQL-Server 2012 で実行できます。
SELECT datekey,
SUM(Amount) OVER(ORDER BY DateKey) AS RunningTotal
FROM document
ただし、DISTINCT
の使用は引き続き許可されていないため、DISTINCTが必要な場合、および/またはアップグレードがオプションでない場合は、OUTER APPLY
が最適なオプションであると思います
上記の David に似たソリューションを使用しますが、一部の行をカウントから除外する必要がある場合は、さらにひねりを加えます。これは、[UserAccountKey]がnullにならないことを前提としています。
-- subtract an extra 1 if null was ranked within the partition,
-- which only happens if there were rows where [Include] <> 'Y'
dense_rank() over (
partition by [Mth]
order by case when [Include] = 'Y' then [UserAccountKey] else null end asc
)
+ dense_rank() over (
partition by [Mth]
order by case when [Include] = 'Y' then [UserAccountKey] else null end desc
)
- max(case when [Include] = 'Y' then 0 else 1 end) over (partition by [Mth])
- 1
ネクロマンシング:
DENSE_RANKを介してMAXでPARTITION BYを介してCOUNT DISTINCTをエミュレートするのは比較的簡単です。
;WITH baseTable AS
(
SELECT 'RM1' AS RM, 'ADR1' AS ADR
UNION ALL SELECT 'RM1' AS RM, 'ADR1' AS ADR
UNION ALL SELECT 'RM2' AS RM, 'ADR1' AS ADR
UNION ALL SELECT 'RM2' AS RM, 'ADR2' AS ADR
UNION ALL SELECT 'RM2' AS RM, 'ADR2' AS ADR
UNION ALL SELECT 'RM2' AS RM, 'ADR3' AS ADR
UNION ALL SELECT 'RM3' AS RM, 'ADR1' AS ADR
UNION ALL SELECT 'RM2' AS RM, 'ADR1' AS ADR
UNION ALL SELECT 'RM3' AS RM, 'ADR1' AS ADR
UNION ALL SELECT 'RM3' AS RM, 'ADR2' AS ADR
)
,CTE AS
(
SELECT RM, ADR, DENSE_RANK() OVER(PARTITION BY RM ORDER BY ADR) AS dr
FROM baseTable
)
SELECT
RM
,ADR
,COUNT(CTE.ADR) OVER (PARTITION BY CTE.RM ORDER BY ADR) AS cnt1
,COUNT(CTE.ADR) OVER (PARTITION BY CTE.RM) AS cnt2
-- Not supported
--,COUNT(DISTINCT CTE.ADR) OVER (PARTITION BY CTE.RM ORDER BY CTE.ADR) AS cntDist
,MAX(CTE.dr) OVER (PARTITION BY CTE.RM ORDER BY CTE.RM) AS cntDistEmu
FROM CTE