按组选择第一行

8
我是一名有用的助手,可以为您进行文本翻译。以下是需要翻译的内容:

我有一个包含三列的表格:A,B,C

这些值是:

+---+-----+----+
| A |  B  | C  |
+---+-----+----+
| 1 | -10 |  5 |
| 1 |   0 |  5 |
| 1 |  10 |  5 |
| 2 |  10 | 12 |
| 2 |   0 | 12 |
| 3 | -10 | 14 |
| 4 |   0 |  8 |
| 4 |  10 |  8 |
| 5 |   0 |  6 |
| 5 |   1 |  6 |
| 5 |  -5 |  6 |
+---+-----+----+

如果我首先按列A、然后按列B、最后按列C排序数据(尽管我已经使每个列A值的列C值相同),那么如何选择每个列A的“第一行”?
因此,这应该得出以下结果:
+---+-----+----+
| A |  B  | C  |
+---+-----+----+
| 1 | -10 |  5 |
| 2 |   0 | 12 |
| 3 | -10 | 14 |
| 4 |   0 |  8 |
| 5 |  -5 |  6 |
+---+-----+----+

{5,-5,6} - Kshitij
1
还可以在dba.stackexchange.com找到详细的答案:按组检索n行,并比较不同方法。 - Vladimir Baranov
这个回答解决了你的问题吗?在每个GROUP BY组中选择第一行? - Michael Freidgeim
2个回答

21
SELECT  a, b, c
FROM    (
        SELECT  *, ROW_NUMBER() OVER (PARTITION BY a ORDER BY b, c) rn
        FROM    mytable
        ) q
WHERE   rn = 1
ORDER BY
        a
或者
SELECT  mi.*
FROM    (
        SELECT  DISTINCT  a
        FROM    mytable
        ) md
CROSS APPLY
        (
        SELECT  TOP 1 *
        FROM    mytable mi
        WHERE   mi.a = md.a
        ORDER BY
                b, c
        ) mi
ORDER BY
        a

在上创建一个复合索引可以加快查询速度。

哪个更有效取决于你的数据分布情况。

如果你有很少不同的值,但每个中有大量记录,则第二个查询会更好。

通过创建带索引的视图可以进一步提高性能:

CREATE VIEW v_mytable_da
WITH   SCHEMABINDING
AS
       SELECT  a, COUNT_BIG(*) cnt
       FROM    dbo.mytable
       GROUP BY
               a

GO

CREATE UNIQUE CLUSTERED INDEX
       pk_vmytableda_a
ON     v_mytable_da (a)

GO

SELECT  mi.*
FROM    v_mytable_da md
CROSS APPLY
        (
        SELECT  TOP 1 *
        FROM    mytable mi
        WHERE   mi.a = md.a
        ORDER BY
                b, c
        ) mi
ORDER BY
        a

非常感谢!喜欢你的第一个答案。 - intrigued_66
有个小问题,我正在使用这个代码作为一个函数,返回一个表格...但是它不允许我包含ORDER BY语句....编辑:没关系,我已经使用了一个过程。 - intrigued_66
@Porcupine:在函数内部使用ORDER BY没有意义。你应该在函数的末尾添加ORDER BY,如下所示:SELECT * FROM myfunction(2) ORDER BY a。如果优化器证明它有效,它会将其推入查询中。 - Quassnoi

1
SELECT *
FROM
  (SELECT *,
          ROW_NUMBER() OVER (PARTITION BY Dealld
                             ORDER BY Price, Dealld) rn
   FROM DealOffers) q
WHERE rn = 1
ORDER BY Name

2
请添加更多信息。我们不鼓励仅包含代码和“尝试此方法”的答案,因为它们没有可搜索的内容,并且没有解释为什么有人应该“尝试此方法”。我们在这里努力成为知识资源。 - abarisone

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接