MySQL:selectN行,但在一列中只有唯一的值

鉴于这个数据集:

ID Name City Birthyear 1 Egon Spengler New York 1957 2 Mac Taylor New York 1955 3 Sarah Connor Los Angeles 1959 4 Jean-Luc Picard La Barre 2305 5 Ellen Ripley Nostromo 2092 6 James T. Kirk Riverside 2233 7 Henry Jones Chicago 1899 

我需要find三个最古老的人,但每个城市只有一个。

如果它只是三个最古老的,那将是…

  • 亨利琼斯/芝加哥
  • Mac Taylor /纽约
  • Egon Spengler /纽约

然而,由于Egon Spengler和Mac Taylor都位于纽约,Egon Spengler将会退出,而下一个(Sarah Connor / Los Angeles)会进来。

优雅的解决scheme?

更新:

目前PConroy的一个变种是最好的/最快的解决scheme:

 SELECT P.*, COUNT(*) AS ct FROM people P JOIN (SELECT MIN(Birthyear) AS Birthyear FROM people GROUP by City) P2 ON P2.Birthyear = P.Birthyear GROUP BY P.City ORDER BY P.Birthyear ASC LIMIT 10; 

对于大数据集(在5分钟后中止),他的原始查询“IN”非常缓慢,但将子查询移动到JOIN会加速很多。 大约需要0.15秒。 在我的testing环境中有1兆行。 我有一个“城市,生日”的索引,第二个就是“生年”。

注意:这与…有关

  • 在一组两种可能性中select唯一的行
  • SQL查询获取最新的价格

可能不是最优雅的解决scheme,并且IN的性能可能在更大的桌子上受损。

嵌套查询得到每个城市的最低Birthyear 。 只有具有此Birthyearlogging在外部查询中匹配。 按年龄sorting,然后限制为3个结果,让你的3个最古老的人谁也是他们的城市最古老(埃贡Spengler退出..)

 SELECT Name, City, Birthyear, COUNT(*) AS ct FROM table WHERE Birthyear IN (SELECT MIN(Birthyear) FROM table GROUP by City) GROUP BY City ORDER BY Birthyear DESC LIMIT 3; +-----------------+-------------+------+----+ | name | city | year | ct | +-----------------+-------------+------+----+ | Henry Jones | Chicago | 1899 | 1 | | Mac Taylor | New York | 1955 | 1 | | Sarah Connor | Los Angeles | 1959 | 1 | +-----------------+-------------+------+----+ 

编辑 – 添加GROUP BY City到外部查询,因为具有相同出生年份的人将返回多个值。 对外部查询进行分组,确保每个城市只有一个结果将被返回,如果不止一个人拥有最低Birthyearct栏将显示在该城市中是否存在多于一个人的Birthyear

这可能不是最优雅和最快的解决scheme,但它应该工作。 我期待看到真正的数据库专家的解决scheme。

 select p.* from people p, (select city, max(age) as mage from people group by city) t where p.city = t.city and p.age = t.mage order by p.age desc 

类似的东西?

 SELECT Id, Name, City, Birthyear FROM TheTable WHERE Id IN (SELECT TOP 1 Id FROM TheTable i WHERE i.City = TheTable.City ORDER BY Birthyear) 

不漂亮,但也应该与同一个dob的多个人一起工作:

testing数据:

 select id, name, city, dob into people from (select 1 id,'Egon Spengler' name, 'New York' city , 1957 dob union all select 2, 'Mac Taylor','New York', 1955 union all select 3, 'Sarah Connor','Los Angeles', 1959 union all select 4, 'Jean-Luc Picard','La Barre', 2305 union all select 5, 'Ellen Ripley','Nostromo', 2092 union all select 6, 'James T. Kirk','Riverside', 2233 union all select 7, 'Henry Jones','Chicago', 1899 union all select 8, 'Blah','New York', 1955) a 

查询:

 select * from people p left join people p1 ON p.city = p1.city and (p.dob > p1.dob and p.id <> p1.id) or (p.dob = p1.dob and p.id > p1.id) where p1.id is null order by p.dob 

@BlaM

更新刚刚发现,它使用USING而不是ON。 它会删除重复的列。

 SELECT P.*, COUNT(*) AS ct FROM people P JOIN (SELECT City, MIN(Birthyear) AS Birthyear FROM people GROUP by City) P2 USING(Birthyear, City) GROUP BY P.City ORDER BY P.Birthyear ASC LIMIT 10; 

原来的post

嗨,我试图用你更新的查询,但我得到错误的结果,直到我已经添加额外的条件join(也join额外的列joinselect)。 转移到您的查询,我使用这个:

 SELECT P.*, COUNT(*) AS ct FROM people P JOIN (SELECT City, MIN(Birthyear) AS Birthyear FROM people GROUP by City) P2 ON P2.Birthyear = P.Birthyear AND P2.City = P.City GROUP BY P.City ORDER BY P.Birthyear ASC LIMIT 10; 

理论上你不需要最后一个GROUP BY P.City,但是现在我已经把它留在这里了,以防万一。 稍后可能会删除它。