SQL Server NTILE - То же значение в другом квартиле - PullRequest
4 голосов
/ 17 февраля 2012

У меня есть сценарий, в котором я разбиваю несколько результатов на кварталы, используя функцию SQL Server NTILE ниже. Цель состоит в том, чтобы в каждом классе было одинаковое количество строк

case NTILE(4) over (order by t2.TotalStd) 
   when 1 then 'A' when 2 then 'B' when 3 then 'C' else 'D' end as Class

Таблица результатов показана ниже, и между 4 классами групп A, B, C и D. (9,9,8,8) разбито.

Есть два результата, которые вызывают у меня проблему, обе строки имеют одинаковое общее стандартное значение 30, но присваиваются различным квартилям.

8   30  A
2   30  B

Мне интересно, есть ли способ гарантировать, что строки с одинаковым значением присваиваются одному квартилю? Могу ли я сгруппировать или разделить по другому столбцу, чтобы получить такое поведение?

Pos TotalStd    class
1   16  A
2   23  A
3   21  A
4   29  A
5   25  A
6   26  A
7   28  A
8   30  A
9   29  A
1   31  B
2   30  B
3   32  B
4   32  B
5   34  B
6   32  B
7   34  B
8   32  B
9   33  B
1   36  C
2   35  C
3   35  C
4   35  C
5   40  C
6   38  C
7   41  C
8   43  C
1   43  D
2   48  D
3   45  D
4   47  D
5   44  D
6   48  D
7   46  D
8   57  D

Ответы [ 4 ]

2 голосов
/ 22 декабря 2016

Вам нужно будет заново создать функцию Ntile, используя функцию ранга.Функция ранга дает одинаковый ранг для строк с одинаковым значением.Позже значение «переходит» на следующий ранг, как если бы вы использовали row_number.Мы можем использовать это поведение для имитации функции Ntile, заставляя ее давать одинаковое значение Ntile для строк с одинаковым значением.Однако - это приведет к тому, что перегородки Ntile будут другого размера.Смотрите пример ниже для нового Ntile, используя 4 корзины:

declare @data table ( x int )

insert @data values 
(1),(2),
(2),(3),
(3),(4),
(4),(5)

select  
    x,
    1+(rank() over (order by x)-1) * 4 / count(1) over (partition by (select 1)) as new_ntile
from @data

Результаты:

x   new_ntile
---------------
1   1
2   1
2   1
3   2
3   2
4   3
4   3
5   4
2 голосов
/ 17 февраля 2012

Не уверен, что вы ожидаете, что произойдет здесь, правда.SQL Server разделил данные на 4 группы как можно большего размера, как вы и просили.Что вы хотите, чтобы произошло?Посмотрите на этот пример:

declare @data table ( x int )

insert @data values 
(1),(2),
(2),(3),
(3),(4),
(4),(5)

select  
    x,
    NTILE(4) over (order by x) as ntile
from @data

Результаты:

x           ntile
----------- ----------
1           1
2           1
2           2
3           2
3           3
4           3
4           4
5           4

Теперь каждая группа разделяет значение с одним (рядом) рядомНо что еще он должен делать?

1 голос
/ 17 февраля 2012

Попробуйте это:

; with a as (
                select TotalStd,Class=case ntile(4)over( order by TotalStd )
                                when 1 then 'A'
                                when 2 then 'B'
                                when 3 then 'C'
                                when 4 then 'D'
                                end
                from t2
                group by TotalStd
)
select d.*, a.Class from t2 d
inner join a on a.TotalStd=d.TotalStd
order by Class,Pos;
0 голосов
/ 31 августа 2017

Здесь у нас есть таблица из 34 строк.

DECLARE @x TABLE (TotalStd INT) 
INSERT @x (TotalStd) VALUES (16), (21), (23), (25), (26), (28), (29), (29), (30), (30), (31), (32), (32), (32), (32), (33), (34), 
    (34), (35), (35), (35), (36), (38), (40), (41), (43), (43), (44), (45), (46), (47), (48), (48), (57)
SELECT '@x', TotalStd FROM @x ORDER BY TotalStd

Мы хотим разделить на квартили. Если мы используем NTILE, размеры сегмента будут примерно одинаковыми (от 8 до 9 рядов в каждом), но связи нарушаются произвольно:

SELECT '@x with NTILE', TotalStd, NTILE(4) OVER (ORDER BY TotalStd) quantile FROM @x

Посмотрите, как 30 появляется дважды: один раз в квантиле 1 и один раз в квантиле 2. Аналогично, 43 появляется в квантилях 3 и 4.

То, что я должен найти, - это 10 предметов в квантиле 1, 8 в квантиле 2, 7 в квантиле 3 и 9 в квантиле 4 (т.е. не идеальное 9-8-9-8, но такое разделение невозможно, если нам не разрешают произвольно разрывать связи). Я могу сделать это, используя NTILE для определения точек отсечения во временной таблице:

DECLARE @cutoffs TABLE (quantile INT, min_value INT, max_value INT)

INSERT @cutoffs (quantile, min_value)
SELECT y.quantile, MIN(y.TotalStd)
FROM (SELECT TotalStd, NTILE(4) OVER (ORDER BY TotalStd) AS quantile FROM @x) y
GROUP BY y.quantile

-- The max values are the minimum values of the next quintiles
UPDATE c1 SET c1.max_value = ISNULL(C2.min_value, (SELECT MAX(TotalStd) + 1 FROM @x))
FROM @cutoffs c1 LEFT OUTER JOIN @cutoffs c2 ON c2.quantile - 1 = c1.quantile

SELECT '@cutoffs', * FROM @cutoffs

Мы будем использовать граничные значения в таблице @cutoffs для создания финальной таблицы:

SELECT x.TotalStd, c.quantile FROM @x x 
    INNER JOIN @cutoffs c ON x.TotalStd >= c.min_value AND x.TotalStd < c.max_value
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...