Sql 如何选择每组的顶部和底部记录?
比如说,我在数据库(SQLServer2008)中有一个表,其中的数据与此类似 (但要大得多): 我想获得每个Sql 如何选择每组的顶部和底部记录?,sql,sql-server-2008,Sql,Sql Server 2008,比如说,我在数据库(SQLServer2008)中有一个表,其中的数据与此类似 (但要大得多): 我想获得每个组的顶部和底部记录的ID,其中每个组的记录按分数排序(补充,ID),如下所示: | GROUP | MIN_ID | MAX_ID | ---------------------------- | A | 10 | 3 | | B | 8 | 8 | | C | 4 | 7 | | D |
组的顶部和底部记录的ID
,其中每个组的记录按分数排序(补充,ID
),如下所示:
| GROUP | MIN_ID | MAX_ID |
----------------------------
| A | 10 | 3 |
| B | 8 | 8 |
| C | 4 | 7 |
| D | 1 | 5 |
问题是:我如何才能做到这一点
到目前为止,我一直在尝试基于RANK()
函数的解决方案,但还没有找到一个既能生成正确的输出,又效率不高或可维护的查询
注:
这个例子被简化了。我的“表”实际上是一个已经很复杂的查询的输出,我希望将最后的阶段添加到其中。我宁愿只从表中选择一次
如果可能,最好有一个通用解决方案,允许我选择每组的顶部和底部n
值
ID
s的顺序不方便
DECLARE @YourTable TABLE (ID INTEGER, Score INTEGER, [Group] VARCHAR(1))
INSERT INTO @YourTable VALUES (10, 1, 'A')
INSERT INTO @YourTable VALUES (6 , 2, 'A')
INSERT INTO @YourTable VALUES (3 , 3, 'A')
INSERT INTO @YourTable VALUES (8 , 5, 'B')
INSERT INTO @YourTable VALUES (4 , 1, 'C')
INSERT INTO @YourTable VALUES (9 , 3, 'C')
INSERT INTO @YourTable VALUES (2 , 4, 'C')
INSERT INTO @YourTable VALUES (7 , 4, 'C')
INSERT INTO @YourTable VALUES (12, 3, 'D')
INSERT INTO @YourTable VALUES (1 , 3, 'D')
INSERT INTO @YourTable VALUES (11, 4, 'D')
INSERT INTO @YourTable VALUES (5 , 6, 'D')
任何解决方案都需要一些关于组和分数的良好索引,但包括ID
SELECT
foo.[Group],
m1.ID AS Min_ID,
m2.ID AS Max_ID
FROM
(
SELECT
[Group], MIN(Score) AS MinScore, MAX(Score) AS MaxScore
FROM
mytable
GROUP BY
[Group]
) foo
JOIN
mytable m1 ON foo.[Group] = m1.[Group] AND foo.MinScore = m1.Score
JOIN
mytable m2 ON foo.[Group] = m2.[Group] AND foo.MaxScore = m2.Score
然而,在您的示例数据中,这也起作用,因为ID和分数是按顺序对齐的:
SELECT
[Group],
MIN(ID) AS Min_ID,
MAX(ID) AS Max_ID
FROM
mytable
GROUP BY
[Group]
任何解决方案都需要一些关于组和分数的良好索引,但包括ID
SELECT
foo.[Group],
m1.ID AS Min_ID,
m2.ID AS Max_ID
FROM
(
SELECT
[Group], MIN(Score) AS MinScore, MAX(Score) AS MaxScore
FROM
mytable
GROUP BY
[Group]
) foo
JOIN
mytable m1 ON foo.[Group] = m1.[Group] AND foo.MinScore = m1.Score
JOIN
mytable m2 ON foo.[Group] = m2.[Group] AND foo.MaxScore = m2.Score
然而,在您的示例数据中,这也起作用,因为ID和分数是按顺序对齐的:
SELECT
[Group],
MIN(ID) AS Min_ID,
MAX(ID) AS Max_ID
FROM
mytable
GROUP BY
[Group]
如果可能,最好有一个通用解决方案,允许我选择每组的顶部和底部n
值
如果可能,最好有一个通用解决方案,允许我选择每组的顶部和底部n
值
您可以使用子查询(选择TOP 1
)…您可以使用子查询(选择TOP 1
)…您希望分数也一样,还是只希望输出按分数排序?TOP 1还是TOP n?差别很大…@j_random_hacker:我不在乎分数。@gbn:是的,我知道。“我会很高兴拿到前1名的。”阿杰·莱恩:如果你不在乎分数,你最好把它们从图片中删掉。看看答案,你的问题会有不同的解释。你是希望分数也一样,还是只希望输出按分数排序?前1名还是前n名?差别很大…@j_random_hacker:我不在乎分数。@gbn:是的,我知道。“我会很高兴拿到前1名的。”阿杰·莱恩:如果你不在乎分数,你最好把它们从图片中删掉。看看答案,你的问题会有不同的解释。在阅读了你的解决方案后,我想我终于明白OP想要什么了。根据他在示例中给出的值,我的解决方案给出的结果与您的解决方案相同。谢谢。是的,他补充了一条评论来澄清。我想我有TDD。。。创造可能有效的最简单的东西。在阅读了你的解决方案后,我想我终于明白OP想要什么了。根据他在示例中给出的值,我的解决方案给出的结果与您的解决方案相同。谢谢。是的,他补充了一条评论来澄清。我想我有TDD。。。创造可能有效的最简单的东西。
WITH q AS
(
SELECT m.*,
ROW_NUMBER() OVER (PARTITION BY Group ORDER BY Score) AS rn_asc,
ROW_NUMBER() OVER (PARTITION BY Group ORDER BY Score DESC) AS rn_desc
FROM mytable m
)
SELECT *
FROM q
WHERE rn_asc BETWEEN 1 AND 10
OR rn_desc BETWEEN 1 AND 10