2

假设我有一张桌子

VAL     PERSON
  1          1
  2          1
  3          1
  4          1
  2          2
  4          2
  6          2
  3          3
  6          3
  9          3
  12         3
  15         3

我想计算每个人的四分位数。

我知道我可以很容易地为一个人计算这些:

SELECT 
    VAL,
    NTILE(4) OVER(ORDER BY VAL) AS QUARTILE
WHERE PERSON = 1;

会给我想要的结果:

VAL    QUARTILE
1      1
2      2
3      3
4      4

问题是,我想为每个人做这个。我知道这样的事情可以完成这项工作:

SELECT 
    PERSON,
    VAL,
    NTILE(4) OVER(ORDER BY VAL) AS QUARTILE
WHERE PERSON = 1
UNION
SELECT 
    PERSON,
    VAL,
    NTILE(4) OVER(ORDER BY VAL) AS QUARTILE
WHERE PERSON = 2
UNION
SELECT 
    PERSON,
    VAL,
    NTILE(4) OVER(ORDER BY VAL) AS QUARTILE
WHERE PERSON = 3
UNION
SELECT 
    PERSON,
    VAL,
    NTILE(4) OVER(ORDER BY VAL) AS QUARTILE
WHERE PERSON = 4

但是如果桌子上有一个新人怎么办?然后我必须更改 SQL 代码。有什么建议么?

4

2 回答 2

5

你为什么不尝试使用分区。

SELECT 
  PERSON,
  VAL,
  NTILE(4) OVER(PARTITION BY PERSON ORDER BY VAL) AS QUARTILE;
FROM TABLE 

问候

于 2018-09-28T18:17:54.880 回答
-1

ntile()不能很好地处理关系。您可以通过一个示例轻松地看到这一点:

select v.x, ntile(2) over (order by x) as tile
from (values (1), (1), (1), (1)) v(x);

返回:

x tile
1   1
1   1
1   2
1   2

相同的价值。不同的瓷砖。如果您要跟踪值所在的磁贴,情况会变得更糟。不同的行在同一查询的不同运行中可以有不同的磁贴——即使数据没有改变。

通常,您希望具有相同值的行具有相同的四分位数,即使图块大小不同。出于这个原因,我建议使用以下方式进行显式计算rank()

select t.*,
       ((seqnum - 1) * 4 / cnt) + 1 as quartile
from (select t.*,
             rank() over (partition by person order by val) as seqnum,
             count(*) over (partition by person) as cnt
      from t
     ) t;

如果您确实希望在图块之间拆分值,请使用row_number()而不是rank().

于 2018-09-28T19:08:15.793 回答