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返回连接表的第一行的主要内容,如果未能解决你的问题,请参考以下文章