1

SQL Server 2012では、列の累積分布を計算するために使用されるCUME_DIST()PERCENT_RANKが導入されたようです。これを実現するための同等の機能がSQLServer2008にありますか?

4

4 に答える 4

3

SQLでは決して言わないでください。

ステートメント:

select percent_rank() over (partition by <x> order by <y>)

基本的に次と同等です。

select row_number() over (partition by <x> order by <y>) / count(*) over (partition by <x>)

基本的に、データに重複がない場合に機能することを意味します。重複があっても十分に近いはずです。

「本当の」答えは、次と同等であるということです。

select row_number() over (partition by <x> order by <y>) / count(distinct <y>) over (partition by <x>)

しかし、関数として count(distinct) はありません。そして、本当に必要でない限り、2008 年に表現するのは苦痛です。

関数 cume_dist() は、累積合計が必要なため難しく、そのためには自己結合が必要です。重複がないと仮定した近似:

with t as (select <x>, <y>,
                  row_number() over (partition by <x> order by <y>) as seqnum
           from <table>
          )
select t.*, sumy*1.0 / sum(sumy) over (partition by <x>)
from (select t.*, sum(tprev.y) as sumy
      from t left outer join
           t tprev
           on t.x = tprev.x and t.seqnum >= tprev.seqnum
     ) t
于 2012-05-16T02:14:12.183 に答える
1

2012 年以前に同等の関数は存在しませんでしたが、少なくとも 32767 行未満のデータ セットの場合、再帰 CTE を使用する回避策が考えられます。ここでは、サイコロのペアが 30 回投げられます。

SET NOCOUNT ON;

DECLARE @t TABLE(i INT);
DECLARE @i INT=0;

WHILE @i<30 BEGIN
INSERT INTO @t VALUES (CAST(RAND()*6 AS INT)+1 + CAST(RAND()*6 AS INT)+1);
    SET @i+=1;
END

DECLARE @tc INT; SELECT @tc=COUNT(*) FROM @t;

WITH a AS (
    SELECT *
    , d=CAST(COUNT(1)OVER(PARTITION BY i ORDER BY i) AS DECIMAL(5,2)) / @tc
    , r=ROW_NUMBER()OVER(ORDER BY i)
    , pr=CAST((RANK()OVER(ORDER BY i)-1)AS DECIMAL(5,2)) / (@tc - 1)
    FROM @t
)
, rcte (i, d, r, cd, pr) AS (
    SELECT i, d, r, d, pr
    FROM a
    WHERE r=1

    UNION ALL

    SELECT a.i, a.d, a.r
    , CASE WHEN rcte.i<>a.i THEN CAST(rcte.cd+a.d AS DECIMAL(5,2)) ELSE rcte.cd END
    , a.pr
    FROM a
    INNER JOIN rcte ON rcte.r + 1 = a.r
)
SELECT i,cd,pr FROM rcte
OPTION (MAXRECURSION 32767)

結果:

i           cd                                      pr
----------- --------------------------------------- ---------------------------------------
2           0.0333333333333                         0.0000000000000
3           0.0700000000000                         0.0344827586206
4           0.2400000000000                         0.0689655172413
4           0.2400000000000                         0.0689655172413
4           0.2400000000000                         0.0689655172413
4           0.2400000000000                         0.0689655172413
4           0.2400000000000                         0.0689655172413
5           0.3100000000000                         0.2413793103448
5           0.3100000000000                         0.2413793103448
6           0.3800000000000                         0.3103448275862
6           0.3800000000000                         0.3103448275862
7           0.5100000000000                         0.3793103448275
7           0.5100000000000                         0.3793103448275
7           0.5100000000000                         0.3793103448275
7           0.5100000000000                         0.3793103448275
8           0.6100000000000                         0.5172413793103
8           0.6100000000000                         0.5172413793103
8           0.6100000000000                         0.5172413793103
9           0.8400000000000                         0.6206896551724
9           0.8400000000000                         0.6206896551724
9           0.8400000000000                         0.6206896551724
9           0.8400000000000                         0.6206896551724
9           0.8400000000000                         0.6206896551724
9           0.8400000000000                         0.6206896551724
9           0.8400000000000                         0.6206896551724
10          0.8700000000000                         0.8620689655172
11          0.9700000000000                         0.8965517241379
11          0.9700000000000                         0.8965517241379
11          0.9700000000000                         0.8965517241379
12          1.0000000000000                         1.0000000000000

以下は、上記の CTE に相当する SQL 2012 です。

SELECT *
, cd=CUME_DIST()OVER(ORDER BY i)
, pr=PERCENT_RANK()OVER(ORDER BY i)
FROM @t;
于 2012-05-16T02:42:10.803 に答える
0

これは非常に近いです。最初のサンプルデータ:

USE tempdb;
GO

CREATE TABLE dbo.DartScores
(
    TournamentID INT,
    PlayerID INT,
    Score INT
);

INSERT dbo.DartScores VALUES
(1, 1, 320),
(1, 2, 340),
(1, 3, 310),
(1, 4, 370),
(2, 1, 310),
(2, 2, 280),
(2, 3, 370),
(2, 4, 370);    

さて、クエリの 2012 バージョン:

SELECT TournamentID, PlayerID, Score, 
  pr = PERCENT_RANK() OVER (PARTITION BY TournamentID ORDER BY Score),
  cd = CUME_DIST()    OVER (PARTITION BY TournamentID ORDER BY Score)
FROM dbo.DartScores
ORDER BY TournamentID, pr;

次の結果が生成されます。

TournamentID PlayerID Score pr                  cd
1            3        310   0                   0.25
1            1        320   0.333333333333333   0.5
1            2        340   0.666666666666667   0.75
1            4        370   1                   1
2            2        280   0                   0.25
2            1        310   0.333333333333333   0.5
2            3        370   0.666666666666667   1
2            4        370   0.666666666666667   1

2005 年の同等物は非常に近いですが、タイをうまく処理できません。申し訳ありませんが、今夜はガス欠です。それ以外の場合は、原因を突き止めたいと思います。Itzik の新しい High Performance window function bookから学んだことと同じくらい知っています。

;WITH cte AS
(
    SELECT TournamentID, PlayerID, Score,
     rk = RANK()   OVER (PARTITION BY TournamentID ORDER BY Score),
     rn = COUNT(*) OVER (PARTITION BY TournamentID)
    FROM dbo.DartScores
)
SELECT TournamentID, PlayerID, Score,
  pr = 1e0*(rk-1)/(rn-1),
  cd = 1e0*(SELECT COALESCE(MIN(cte2.rk)-1, cte.rn)
    FROM cte AS cte2 WHERE cte2.rk > cte.rk) / rn
FROM cte;

次の結果が生成されます (同順位の cume_dist 値がわずかに変化することに注意してください)。

TournamentID PlayerID Score pr                  cd
1            3        310   0                   0.25
1            1        320   0.333333333333333   0.5
1            2        340   0.666666666666667   0.75
1            4        370   1                   1
2            2        280   0                   0.25
2            1        310   0.333333333333333   0.5
2            3        370   0.666666666666667   0.75
2            4        370   0.666666666666667   0.75

クリーンアップすることを忘れないでください:

DROP TABLE dbo.DartScores;
于 2012-05-16T02:15:56.457 に答える
0

はい、少なくとも percent_rank() 部分については、簡単な解決策があります。使用できます

(rank() over (partition by <x> order by <y>)-1)/(count(*) over (partition by <x>)-1)

これにより、次の場合とまったく同じ結果が得られます

percent_rank() over (partition by <x> order by <y>)

rank() 関数は、SQL Server 2008 に既に存在する数少ない分析関数の 1 つです。

于 2015-09-30T15:27:34.810 に答える