如何使用SQL转换以下数据:
cat score
1 2
1 3
2 1
2 3
2 5
3 1
3 2
3 3
3 4
创建以下子集:
cat score1 score2
1 2 3
2 1 3
3 1 2
因此,只有“cat”列中每个值的前两个分数才会被放入转换后的表格中。
答案 0 :(得分:2)
一种可能的方法是在cat上使用自联接但是a.score< b。分数,以便从b获得下一个最小值。如果你需要做n级深度,这不能很好地扩展。在这种情况下,使用模拟行号的用户变量对每列进行条件聚合可能会更好。
这假设Score1 - X始终是您想要显示最低到最高分数。如果需要,我们也可以从最高到最低,或者我们可以使用规则来管理哪些被选中。
样本:http://rextester.com/NHDS97935
SELECT A.cat, Min(A.score) score1, min(B.Score) score2
FROM SO46102892 A
INNER JOIN SO46102892 B
on A.cat = B.Cat
and A.score < B.Score
GROUP BY a.cat;
,并提供:
+----+-----+--------+--------+
| | cat | score1 | score2 |
+----+-----+--------+--------+
| 1 | 1 | 2 | 3 |
| 2 | 2 | 1 | 3 |
| 3 | 3 | 1 | 2 |
+----+-----+--------+--------+
或者(因为这会提供更好的n分数缩放方法)
DEMO:http://rextester.com/VLCC24693
只需在外部选择中添加一个case语句,即可处理n个得分更多。
在这种情况下,我们通过使用两个用户变量并根据需要调整其值来模拟row_number () over (partition by cat order by cat, score)
。
单独运行此部分:
SELECT case when cat=@cat then @RN:=@RN+1 else @RN:=1 end RN
, case when cat=@cat then @cat else @cat:=cat end cat
, score
FROM (SELECT * FROM SO46102892 ORDER BY cat, score) A
CROSS JOIN (SELECT @RN:=0, @Cat:=0) z
您可以看到每个RN如何为模拟其他RDBMS中提供的row_number功能的每个类别分配1-x。
SELECT cat
, max(case when RN = 1 then score end) as Score1
, max(case when RN = 2 then score end) as Score2
, max(case when RN = 3 then score end) as Score3
, max(case when RN = 4 then score end) as Score4
, max(case when RN = 5 then score end) as Score5
FROM (SELECT case when cat=@cat then @RN:=@RN+1 else @RN:=1 end RN
, case when cat=@cat then @cat else @cat:=cat end cat
, score
FROM (SELECT * FROM SO46102892 ORDER BY cat, score) A
CROSS JOIN (SELECT @RN:=0, @Cat:=0) z
) y
GROUP BY cat
ORDER BY cat;
给我们:
+----+-----+--------+--------+--------+--------+--------+
| | cat | Score1 | Score2 | Score3 | Score4 | Score5 |
+----+-----+--------+--------+--------+--------+--------+
| 1 | 1 | 2 | 3 | NULL | NULL | NULL |
| 2 | 2 | 1 | 3 | 5 | NULL | NULL |
| 3 | 3 | 1 | 2 | 3 | 4 | NULL |
+----+-----+--------+--------+--------+--------+--------+
我们可以通过从外部选择中删除它来排除得分3,4,5。