MySQL返回连接表的第一行

Posted

技术标签:

【中文标题】MySQL返回连接表的第一行【英文标题】:MySQL return first row of a joined table 【发布时间】: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 评分最高(集合中最高的鸭子评分) 【参考方案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

以上是关于MySQL返回连接表的第一行的主要内容,如果未能解决你的问题,请参考以下文章

仅当右表为空时,LEFT JOIN 才返回左表的第一行

Mysql - 仅返回具有相同唯一 ID 的第一行

MySQL左连接不返回连接表的空值

Perl 和 MySQL - 使用 DBI 从表的最后一行返回字段,可能带有 last_insert_id?

mysql返回数据量超过全表的30%

Mysql中的多连接表仅返回一行[重复]