web-dev-qa-db-ja.com

よりインテリジェントなntile

ntile()ウィンドウ関数を使用する場合の主な問題は、実際の値に関係なく、ほぼ等しい部分に任意にグループ化されることです。

たとえば、次のクエリの場合:

_select
    id,title,price,
    row_number() over(order by price) as row_number,
    rank() over(order by price) as rank,
    count(*) over(order by price) as count,
    dense_rank() over(order by price) as dense_rank,
    ntile(10) over(order by price) as decile
from paintings
order by price;
_

サイズがほぼ同じ10個のグループを取得します。同じ価格の絵画が最終的に別のビンに入れられる可能性が非常に高くなります。

例えば:

_┌────┬────────────────────────────────────────────┬───────┬────────────┬──────┬───────┬────────────┬────────┐
│ id │ title                                      │ price │ row_number │ rank │ count │ dense_rank │ decile │
╞════╪════════════════════════════════════════════╪═══════╪════════════╪══════╪═══════╪════════════╪════════╡
│ 11 │ Eyes in the Heat                           │ 10    │ 1          │ 1    │ 1     │ 1          │ 1      │
│ 19 │ Deux fillettes, fond jaune et rouge        │ 11    │ 2          │ 2    │ 2     │ 2          │ 1      │
│ 17 │ Flowers in a Pitcher                       │ 12    │ 3          │ 3    │ 6     │ 3          │ 1      │
│ 5  │ Composition with Red, Yellow and Blue      │ 12    │ 4          │ 3    │ 6     │ 3          │ 2      │
│ 18 │ La lecon de musique (The Music Lesson)     │ 12    │ 5          │ 3    │ 6     │ 3          │ 2      │
│ 9  │ The Adoration of the Magi                  │ 12    │ 6          │ 3    │ 6     │ 3          │ 2      │
│ 29 │ Self-Portrait                              │ 14    │ 7          │ 7    │ 10    │ 4          │ 3      │
│ 25 │ Symphony in White, No. 1: The White Girl   │ 14    │ 8          │ 7    │ 10    │ 4          │ 3      │
│ 30 │ The Anatomy Lecture of Dr. Nicolaes Tulp   │ 14    │ 9          │ 7    │ 10    │ 4          │ 3      │
│ 20 │ Les repasseuses (Women Ironing)            │ 14    │ 10         │ 7    │ 10    │ 4          │ 4      │
│ 1  │ The Birth of Venus                         │ 15    │ 11         │ 11   │ 14    │ 5          │ 4      │
│ 12 │ Femme se promenant dans une foret exotique │ 15    │ 12         │ 11   │ 14    │ 5          │ 4      │
│ 24 │ Portrait of the Painter’s Mother           │ 15    │ 13         │ 11   │ 14    │ 5          │ 5      │
│ 28 │ Jeunes filles au piano                     │ 15    │ 14         │ 11   │ 14    │ 5          │ 5      │
│ 7  │ Portrait de l artiste (Self-portrait)      │ 16    │ 15         │ 15   │ 17    │ 6          │ 5      │
│ 3  │ The Last Supper                            │ 16    │ 16         │ 15   │ 17    │ 6          │ 6      │
│ 13 │ Combat of a Tiger and a Buffalo            │ 16    │ 17         │ 15   │ 17    │ 6          │ 6      │
│ 4  │ The Creation of Man                        │ 17    │ 18         │ 18   │ 19    │ 7          │ 6      │
│ 22 │ Le Chemin de Fer                           │ 17    │ 19         │ 18   │ 19    │ 7          │ 7      │
│ 6  │ Femmes de Tahiti [Sur la plage]            │ 18    │ 20         │ 20   │ 24    │ 8          │ 7      │
│ 21 │ Le Bar aux Folies-Berg                     │ 18    │ 21         │ 20   │ 24    │ 8          │ 7      │
│ 26 │ Lady at the Piano                          │ 18    │ 22         │ 20   │ 24    │ 8          │ 8      │
│ 15 │ Remembrance of a Garden                    │ 18    │ 23         │ 20   │ 24    │ 8          │ 8      │
│ 16 │ 1914                                       │ 18    │ 24         │ 20   │ 24    │ 8          │ 8      │
│ 14 │ Ancient Sound, Abstract on Black           │ 19    │ 25         │ 25   │ 28    │ 9          │ 9      │
│ 8  │ The Large Turf                             │ 19    │ 26         │ 25   │ 28    │ 9          │ 9      │
│ 23 │ On the Beach                               │ 19    │ 27         │ 25   │ 28    │ 9          │ 9      │
│ 2  │ Portrait of Mona Lisa                      │ 19    │ 28         │ 25   │ 28    │ 9          │ 10     │
│ 27 │ On the Terrace                             │ 20    │ 29         │ 29   │ 30    │ 10         │ 10     │
│ 10 │ The She-Wolf                               │ 20    │ 30         │ 29   │ 30    │ 10         │ 10     │
└────┴────────────────────────────────────────────┴───────┴────────────┴──────┴───────┴────────────┴────────┘
_

価格が_12_のアイテムが4つあるが、2つは十分位数1にあり、2つは十分位2にあることに注意してください。これらのアイテムをまとめておきたいのですが、どの十分位数に悩んでいません。

比較を行うために他のウィンドウ関数を含めました。

ntile()row_number()のみを使用し、それを基準にカットオフを行っているようです。 rank()関数またはcount(*)関数のいずれかを使用した場合、同じ価格のアイテムは同じビンに入れられるため、より公平になります。

これは、PostgreSQLとSQL Serverの両方の動作で、おそらく残りの動作です。

問題は、これを達成する方法はありますか?

5
Manngo

rank()を使用して、各ビンの行数で整数除算を行うことができます。

declare @T table(id int, title varchar(100), price int);

insert into @T(id, title, price) values
(19, 'Deux fillettes, fond jaune et rouge        ', 11),
(17, 'Flowers in a Pitcher                       ', 12),
(5 , 'Composition with Red, Yellow and Blue      ', 12),
(18, 'La lecon de musique (The Music Lesson)     ', 12),
(9 , 'The Adoration of the Magi                  ', 12),
(29, 'Self-Portrait                              ', 14),
(25, 'Symphony in White, No. 1: The White Girl   ', 14),
(30, 'The Anatomy Lecture of Dr. Nicolaes Tulp   ', 14),
(20, 'Les repasseuses (Women Ironing)            ', 14),
(1 , 'The Birth of Venus                         ', 15),
(12, 'Femme se promenant dans une foret exotique ', 15),
(24, 'Portrait of the Painter’s Mother           ', 15),
(28, 'Jeunes filles au piano                     ', 15),
(7 , 'Portrait de l artiste (Self-portrait)      ', 16),
(3 , 'The Last Supper                            ', 16),
(13, 'Combat of a Tiger and a Buffalo            ', 16),
(4 , 'The Creation of Man                        ', 17),
(22, 'Le Chemin de Fer                           ', 17),
(6 , 'Femmes de Tahiti [Sur la plage]            ', 18),
(21, 'Le Bar aux Folies-Berg                     ', 18),
(26, 'Lady at the Piano                          ', 18),
(15, 'Remembrance of a Garden                    ', 18),
(16, '1914                                       ', 18),
(14, 'Ancient Sound, Abstract on Black           ', 19),
(8 , 'The Large Turf                             ', 19),
(23, 'On the Beach                               ', 19),
(2 , 'Portrait of Mona Lisa                      ', 19),
(27, 'On the Terrace                             ', 20),
(10, 'The She-Wolf                               ', 20);

declare @BinCount int = 10;
declare @BinSize int;
select @BinSize = 1 + count(*) / @BinCount from @T;

select T.id,
       T.title,
       T.price,
       1 + rank() over(order by T.price) / @BinSize as decile
from @T as T;

結果:

id  title                                       price  decile
--- ------------------------------------------- ------ --------------------
19  Deux fillettes, fond jaune et rouge         11     1
17  Flowers in a Pitcher                        12     1
5   Composition with Red, Yellow and Blue       12     1
18  La lecon de musique (The Music Lesson)      12     1
9   The Adoration of the Magi                   12     1
29  Self-Portrait                               14     3
25  Symphony in White, No. 1: The White Girl    14     3
30  The Anatomy Lecture of Dr. Nicolaes Tulp    14     3
20  Les repasseuses (Women Ironing)             14     3
1   The Birth of Venus                          15     4
12  Femme se promenant dans une foret exotique  15     4
24  Portrait of the Painter’s Mother            15     4
28  Jeunes filles au piano                      15     4
7   Portrait de l artiste (Self-portrait)       16     5
3   The Last Supper                             16     5
13  Combat of a Tiger and a Buffalo             16     5
4   The Creation of Man                         17     6
22  Le Chemin de Fer                            17     6
6   Femmes de Tahiti [Sur la plage]             18     7
21  Le Bar aux Folies-Berg                      18     7
26  Lady at the Piano                           18     7
15  Remembrance of a Garden                     18     7
16  1914                                        18     7
14  Ancient Sound, Abstract on Black            19     9
8   The Large Turf                              19     9
23  On the Beach                                19     9
2   Portrait of Mona Lisa                       19     9
27  On the Terrace                              20     10
10  The She-Wolf                                20     10

そして、私はどの十進法に悩まされていません

サンプルデータを含むビン2と8が空になったことに注意してください。

5
Mikael Eriksson

WIDTH_BUCKET関数をシミュレートできます。

CREATE FUNCTION dbo.width_bucket(@val decimal, @min_val decimal, @max_val decimal, @groups int)
RETURNS int
AS
BEGIN
    DECLARE @res int;

    IF @val = @max_val RETURN @groups;

    RETURN CAST((@val - @min_val) / ((@max_val - @min_val) / @groups) AS int) + 1;
END

SELECT
    id, title, price, dbo.width_bucket(price, 11.0, 20.0, 10)
FROM
    t;

または関数なし:

DECLARE @groups int = 10;

WITH mm AS
(
    SELECT MIN(price) AS min_price, MAX(price) AS max_price
    FROM   t
)
SELECT
    id, title, price,
    CASE
        WHEN 
            price = max_price THEN @groups
        ELSE
            CAST((price - min_price) / ((max_price - min_price) / @groups) AS int) + 1
    END as ngroup
FROM
    t
CROSS APPLY (SELECT min_price, max_price FROM mm) mm;

注価格タイプをintからdecimalに変更しました

 id |タイトル|価格| ngroup 
-:| :----------------------------------------- :---- | -----:
 19 | Deuxフィレット、好きなジョーンとルージュ| 11.00 | 1 
 17 |ピッチャーの花| 12.00 | 2 
 5 |赤、黄、青の合成| 12.00 | 2 
 18 | La lecon de musique(音楽レッスン)| 12.00 | 2 
 9 |賢者の礼拝| 12.00 | 2 
 29 |自画像| 14.00 | 4 
 25 |白の交響曲第1番:白い少女| 14.00 | 4 
 30 |ニコラエス・タルプ博士の解剖学講義| 14.00 | 4 
 20 | Les repasseuses(女性アイロン)| 14.00 | 4 
 1 |金星の誕生| 15.00 5 
 12 | Femme se promenant dans une foret exotique | 15.00 5 
 24 |画家の母の肖像| 15.00 5 
 28 |ジューンはauピアノを埋めます| 15.00 5 
 7 | Portrait de l artiste(自画像)| 16.00 | 6 
 3 |最後の晩餐| 16.00 | 6 
 13 |タイガーとバッファローの戦闘| 16.00 | 6 
 4 |人間の創造| 17.00 | 7 
 22 |ルシュマンドフェル| 17.00 | 7 
 6 |フェムスデタヒチ[シュールラプラージュ] | 18.00 | 8 
 21 | Le Bar aux Folies-Berg | 18.00 | 8 
 26 |ピアノの女性| 18.00 | 8 
 15 |庭の記憶| 18.00 | 8 
 16 | 1914年18.00 | 8 
 14 |エンシェントサウンド、アブストラクトブラック| 19.00 | 9 
 8 |大きな芝| 19.00 | 9 
 23 |ビーチで| 19.00 | 9 
 2 |モナリザの肖像|写真モナリザの肖像19.00 | 9 
 27 |テラスで| 20.00 | 10 
 10 |シーウルフ| 20.00 | 10 

db <> fiddle ---(ここ

1
McNets

私は答えを受け入れましたが、私がどのように答えを実践したかを説明したいと思います。

_WITH data AS (SELECT count(*)/10.0 AS bin FROM prints WHERE price<20)
SELECT
    id,title,price,
    row_number() OVER(ORDER BY price) AS row_number,
    ntile(10) OVER(ORDER BY price) AS decile,
    floor((row_number() OVER(ORDER BY price)-1)/bin)+1 AS row_decile,
    floor((rank() OVER(ORDER BY price)-1)/bin)+1 AS rank_decile,
    floor((count(*) OVER(ORDER BY price)-1)/bin)+1 AS count_decile,
    bin
FROM prints,data
WHERE price<20
ORDER BY price;
_

興味がある点:

  • 結果をよりDBニュートラルにするために、ビンサイズを変数ではなくCTEに入れました。
  • WHERE句は、扱いにくいビンサイズを強制するためのものです。 _10.0_は、切り捨てられた整数ではなく、10進数を生成します。
  • row_number()/bin+1計算は、ネイティブのntile関数を複製するために含まれています。

もちろん、行数が比較的少ない場合は十分位数が欠落するリスクがありますが、少なくとも同じ値を保持します。

今では、どちらのオプションが自分の好みに合っているかを決めることが重要です。

フィドル: http://sqlfiddle.com/#!17/d50f75/2

0
Manngo