每组选择一行而不指定顺序?

时间:2013-05-01 04:56:36

标签: sql sql-server ranking-functions

假设我有这些数据:

create table People (ID int identity, Name nvarchar(50), Age int);   
insert into People values 
  ('Bill Jones', 50),
  ('Bill Jones', 12),
  ('Sam Smith', 23),
  ('Jill Brown', 44),
  ('Jill Brown', 67),
  ('Jill Brown', 3)

这个查询:

select * from (
   select 
       ID, Name, Age, 
       row_number() over (partition by Name order by ID) [rownum]
   from People
) a where [rownum] = 1

每个唯一名称成功返回一个人。

ID  NAME        AGE ROWNUM
1   Bill Jones  50  1
4   Jill Brown  44  1
3   Sam Smith   23  1

但是,为了使用row_number(),我必须指定order by,导致查询计划包含昂贵的排序操作。

query plan

我不关心返回哪个的人;我每个名字只需要一个人。

有没有办法在没有排序的情况下做到这一点?

您可以在此处查看我的查询和执行计划:http://sqlfiddle.com/#!3/3ee32/1/0

4 个答案:

答案 0 :(得分:2)

我不知道它是否优化了但它显示了你想要的记录......没有订单条款/.....

Select * from People a where id in (Select Top(1) id from people b where name in
                                  (Select name from people group by name) and a.name=b.name)

Sql Fidddle Demo Link

答案 1 :(得分:1)

查询怎么样:

select 
    distinct Name, 
    (Select top 1 Age from People b where b.Name=a.Name) Age 
from People a

OR

select b.* From(
    select min(ID) ID from people group by Name
    ) a inner join People b on a.ID=b.ID

包含所有列。 事实:这些查询都没有超过ROW_NUMBER()的查询!

答案 2 :(得分:1)

您可以考虑以下问题:

SELECT 
  a.* 
FROM 
  People a 
LEFT JOIN 
  People b 
ON
  (a.Name = b.Name AND a.id > b.id) 
WHERE b.id IS NULL

当我在SQLFiddle中运行它时,它似乎表现得更好:

原始查询:0.0146747

自我加入:0.0071784

答案 3 :(得分:1)

我实际上看到了编写原始查询的不同方法。您还可以考虑使用Common Table Expression。虽然我相信优化水平几乎相同。我确实更喜欢CTE

with cte
as
(
    select ID, Name, Age, 
           row_number() over (partition by Name order by ID) [rownum]
    from People
)

select * 
from cte 
where [rownum] = 1