2009-12-23 88 views
15

我正在寻找一种方法来处理以下情形。我有一个数据库表,我需要为表中包含的每个“组ID”只返回一条记录,而且每个组中选择的记录应该是家中最老的人。SQL查询每个组只返回1条记录ID

ID Group ID Name    Age 
1 134  John Bowers  37 
2 134  Kerri Bowers  33 
3 135  John Bowers  44 
4 135  Shannon Bowers  42 

所以在上面提供的示例数据中,我需要ID 1和3返回,因为它们是每个组ID中最老的人。

这是针对SQL Server 2005数据库查询的。

+0

如果你想要这个名字,如果你有> 1个年龄最大的人,你仍然有机会选择> 1行。在这种情况下,你也应该建立标准名称。 – 2009-12-23 17:36:26

+0

好点克里斯。是试图简化这个问题一点,但是留下这样的漏洞:-)我其实有一个性别领域,所以我正在寻找选择一个家庭中最老的男性。如果有男性,那么最老的女性。如果同一家庭中有两名男性同龄,那么我只需要选择其中的一项。这可以基于简单的事情,就像打破决斗者身份证号码最低的人那样简单。 – 2009-12-23 17:50:59

+1

Joe Celko的优秀着作“SQL for Smarties”第21.4节“极值函数”中有一个很好的讨论。如果你要碰到比简单的SELECT和INSERT更棘手的事情,我强烈推荐本书。 – shoover 2009-12-23 18:05:09

回答

21
SELECT t.* 
FROM (
     SELECT DISTINCT groupid 
     FROM mytable 
     ) mo 
CROSS APPLY 
     (
     SELECT TOP 1 * 
     FROM mytable mi 
     WHERE mi.groupid = mo.groupid 
     ORDER BY 
       age DESC 
     ) t 

或本:

SELECT * 
FROM (
     SELECT *, ROW_NUMBER() OVER (PARTITION BY groupid ORDER BY age DESC) rn 
     FROM mytable 
     ) 
WHERE rn = 1 

这甚至关系的情况下返回每组最多一个记录。

对于这两种方法的性能比较请参见这篇文章中我的博客:

+0

+1:是的,忘了我关于领带的声明。太忙的战斗火灾。 – 2009-12-23 17:41:19

+0

感谢Quassnoi。我能够将性别列添加到ORDER By子句的年龄列中,并获得我期待的结果! (我的第一个问题后,性别专栏只在评论中讨论)您的解决方案非常完美,适应性强! – 2009-12-23 17:57:14

+0

跟进问题。这些将以17500万条记录运行。其中一个或另一个查询是否更高效? – 2009-12-23 18:00:43

0
SELECT GroupID, Name, Age 
FROM table 
INNER JOIN 
(
SELECT GroupID, MAX(Age) AS OLDEST 
FROM table 
) AS OLDESTPEOPLE 
ON 
table.GroupID = OLDESTPEOPLE.GroupID 
AND 
table.Age = OLDESTPEOPLE.OLDEST 
3

用途:

SELECT DISTINCT 
     t.groupid, 
     t.name 
    FROM TABLE t 
    JOIN (SELECT t.groupid, 
       MAX(t.age) 'max_age' 
      FROM TABLE t 
     GROUP BY t.groupid) x ON x.groupid = t.groupid 
          AND x.max_age = t.age 

那么,如果有2+人一个组的同一年龄?存储出生日期而不是年龄会更好 - 您可以始终计算出示日期的出生日期。

+0

小心领带! – Quassnoi 2009-12-23 17:39:49

0

试试这个(假设集团是同义词家用

Select * From Table t 
Where Age = (Select Max(Age) 
      From Table 
      Where GroupId = t.GroupId) 

如果有两个或多个“最老”的人,一些家庭(他们都是相同年龄和有其他人没有人老),那么这将返回所有这些,而不是随机一个。

如果这是一个问题,那么您需要添加另一个子查询以返回该集合中某个人的任意键值。

Select * From Table t 
Where Id = 
    (Select Max(Id) Fom Table 
    Where GroupId = t.GroupId 
     And Age = 
     (Select(Max(Age) From Table 
      Where GroupId = t.GroupId))