web-dev-qa-db-ja.com

合計カウントに対する一意のカウントの実行比率

T-SQL(SQL Server 2017 Community Edition以降)で順序付けられた観測値(行)のカウント(一意および合計)の実行比率をコーディングする方法に関するアイデアはありますか?

必然的に順序付けられるデータセットが与えられた場合(例:日付でインデックス付け/順序付けされた時系列):

CREATE TABLE #x (dt DATE, Name VARCHAR(MAX));
INSERT INTO #x VALUES
('2012-01-01', 'a'),('2012-01-02', 'b'),('2012-01-03', 'c'),
('2012-01-04', 'a'),('2012-01-05', 'b'),('2012-01-06', 'd'),
('2012-01-07', 'a'),('2012-01-08', 'b'),('2012-01-09', 'e'),('2012-01-10', 'e');

したがって、列DtNamesが与えられた場合、以下の出力Ratioが必要です。わかりやすくするために、現在までの一意の名前をカウントする出力列UCnt(つまり、制限された実行カウント)と、現在までのすべての名前をカウントする(つまり、単純な実行カウント)TCntも含めました。出力Ratioフィールドは、2つの実行比率です。

Dt          Name    UCnt    TCnt    Ratio
2012-01-01  a       1       1       1.000
2012-01-02  b       2       2       1.000
2012-01-03  c       3       3       1.000
2012-01-04  a       3       4       0.750
2012-01-05  b       3       5       0.600
2012-01-06  d       4       6       0.666
2012-01-07  a       4       7       0.571
2012-01-08  b       4       8       0.500
2012-01-09  e       5       9       0.555
2012-01-10  e       5       10      0.500
1
Oleg Melnikov

Lamakに感謝します。 OUTER APPLY 2時間以上実行されました(約100万行)。私はそれを殺さなければなりませんでした。これが同じサイズのテーブルで約30秒かかる私のソリューションです。

WITH y AS (-- count dupped Names and each observation
    SELECT dt, Name,
    UCnt_=COUNT(*) OVER (PARTITION BY Name ORDER BY Dt), 
    TCnt=ROW_NUMBER() OVER (ORDER BY Dt)
    FROM #x
),
z AS (-- count unique Names only
    SELECT *,
    UCnt=SUM(CASE WHEN UCnt_>1 THEN 0 ELSE 1 END) OVER (ORDER BY Dt) 
    FROM y
)
SELECT Dt, Name, UCnt_, UCnt, TCnt, Ratio=UCnt/1.0/TCnt
FROM z
ORDER BY Dt

出力:

Dt          Name    UCnt_   UCnt    TCnt    Ratio
2012-01-01  a       1       1       1       1.000
2012-01-02  b       1       2       2       1.000
2012-01-03  c       1       3       3       1.000
2012-01-04  a       2       3       4       0.750
2012-01-05  b       2       3       5       0.600
2012-01-06  d       1       4       6       0.666
2012-01-07  a       3       4       7       0.571
2012-01-08  b       3       4       8       0.500
2012-01-09  e       1       5       9       0.555
2012-01-10  e       2       5       10      0.500
0
Oleg Melnikov

OUTER APPLYROW_NUMBERの組み合わせでうまくいくようです。

WITH CTE AS
(
    SELECT  *,
            Tot_Cnt = ROW_NUMBER() OVER(ORDER BY dt)
    FROM #x
)
SELECT  A.dt,
        A.[Name],
        B.Unq_Cnt,
        A.Tot_Cnt,
        Ratio_of_Cnts = CONVERT(NUMERIC(10,4),B.Unq_Cnt)/A.Tot_Cnt 
FROM CTE A
OUTER APPLY (SELECT Unq_Cnt = COUNT(DISTINCT [Name]) 
             FROM CTE
             WHERE dt <= A.dt) B
;

これのデモ です。

4
Lamak