假设我有一张桌子
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代码。有什么建议吗?
答案 0 :(得分:5)
为什么不尝试使用分区依据。
SELECT
PERSON,
VAL,
NTILE(4) OVER(PARTITION BY PERSON ORDER BY VAL) AS QUARTILE;
FROM TABLE
问候
答案 1 :(得分:-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()
。