【问题标题】:MySQL return first row of a joined tableMySQL返回连接表的第一行
【发布时间】:2012-03-22 11:35:29
【问题描述】:

我有两个表(国家和鸭子),其中国家表包含世界上的每个国家,鸭子表有一个鸭子列表,其中包含一个 country_id 字段以链接到主要国家/地区。

我正在尝试获取仅包含至少一只鸭子的国家/地区的列表,并从鸭子表中获得该国家内评分最高的鸭子的单个匹配记录。到目前为止,我有:

SELECT *
FROM country c 
INNER JOIN ducks d ON c.id = d.country_id
ORDER BY c.country ASC, d.rating DESC

这会返回每只鸭子的列表,而不是每个国家/地区一个。

如果有人能在这里指出正确的方向,我将不胜感激。我宁愿在 SQL 中执行此操作,也不愿为每个国家/地区单独查询以选出评分最高的鸭子。

【问题讨论】:

  • 请参阅:xaprb.com/blog/2006/12/07/…,了解如何执行此操作的示例。
  • 你想要哪只鸭子?只是任何人?
  • @dotoree 评分最高(集合中最高的鸭子评分)

标签: php mysql sql join greatest-n-per-group


【解决方案1】:
SELECT c.*, d.*
FROM country c 
  INNER JOIN ducks d 
    ON d.id =                         --- guessing the ducks Primary Key here
       ( SELECT dd.id                 --- and here  
         FROM ducks dd
         WHERE c.id = dd.country_id
         ORDER BY dd.rating DESC
         LIMIT 1
       )

MyISAM 表的(country_id, rating, id) 或InnoDB 表的(country_id, rating) 上的索引会有所帮助。

此查询将在每个国家/地区仅显示一个duck,即使有多个具有相同评级。如果您希望出现评分并列的鸭子,请使用@imm 的GROUP BY 答案。

【讨论】:

  • +1 非常好。有没有可能在没有子查询的情况下实现这一点?
  • @J.Bruni:是的,如果你还有一个连接,就像 Naltharial 的答案(实际上是一个带有 Where-Is-Null 检查的左连接。)
【解决方案2】:

您可以尝试只添加一个选择连接,用于

SELECT c.*, d.*
FROM country c 
INNER JOIN ducks d ON c.id = d.country_id
LEFT JOIN ducks d2 ON d.country_id = d2.country_id AND d2.rating > d.rating
WHERE d2.id IS NULL

【讨论】:

  • 最好有SELECT c.*, d.*。无需包含 d2.* 列 - 这将全部为 NULL。
  • 删除子查询很有趣,但是如果ducks 表足够大,这个版本看起来会非常慢并且消耗内存。因为它在 count(ducks)*count(ducks) 集合上运行
  • 修复:它在count(ducks)*(count(ducks)-1) 集合上运行(不是整个ducks,而是每个country_id)。好吧,用country_id隔开就没有那么可怕了。但是如果使用正确的索引,@imm 解决方案应该会更有效
  • @zxcat:这根本不是这个查询的复杂性所在。如果仅查看您正在查询的空间,则对评级进行分组和比较的操作要昂贵得多。子查询几乎永远不会比JOIN 快,尤其是在这种情况下,后者使用eq_ref 与子查询的index 进行比较(在理想情况下)。对查询运行EXPLAIN SELECT 并比较执行计划。
【解决方案3】:

你可以试试:

SELECT c.*, d.*
FROM country c
INNER JOIN (
    SELECT d.country_id, d.id, MAX(d.rating) AS rating
    FROM ducks d
    GROUP BY d.country_id
) q ON (q.country_id = c.id)

INNER JOIN ducks d 
    ON (d.country_id, d.rating) = (q.country_id, q.rating)

【讨论】:

  • 这只需要再加入一个即可显示鸭子的详细信息:INNER JOIN ducks d ON (d.country_id, d.rating) = (q.country_id, q.rating)
【解决方案4】:

试试这个:

SELECT c.country, MAX(d.rating) AS max_rating
FROM country c
JOIN ducks d ON c.id = d.country_id
GROUP BY c.id
ORDER BY c.country ASC

如果“最高评分”为 1,则将 MAX(d.rating) 更改为 MIN(d.rating)

【讨论】:

  • 嗨,这非常接近,因为它返回一个具有最高评级的国家,我正在尝试返回与该最高评级对应的记录。例如,如果我将您的代码的第一行更改为 SELECT c.country, d.id, d.rating, MAX(d.rating),那么 d.rating 并不总是等于 MAX(d.rating),如果这有意义的话
  • @ypercube:谢谢。没关系......我现在不能在这里测试它。我想让它在没有子查询的情况下发生。现在OP已经解决了他的案子......
【解决方案5】:

许多数据库都有“select top 10 * from...”的等价物。在 mySql 中,语法是“select * from ... limit 10”。

...但是...

在这种情况下,你真的想要“group by”和“max()”!

【讨论】:

  • 嗨,group by 限制了结果,但是 MAX() 函数只显示组的最大值,但行的其余部分包含 MySQL 找到的第一条记录的数据,而不是一个具有最高评级。这是我到目前为止所拥有的:SELECT c.*, d.*, MAX(d.rating) FROM country c INNER JOIN ducks d ON c.id = d.country_id GROUP BY c.country ORDER BY c.country ASC, d.rating DESC
猜你喜欢
  • 2013-02-18
  • 2021-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多