从 MySQL 中的表中加入单行
Posted
技术标签:
【中文标题】从 MySQL 中的表中加入单行【英文标题】:Join single row from a table in MySQL 【发布时间】:2011-03-08 10:02:45 【问题描述】:我有两张桌子players
和scores
。
我想生成一个看起来像这样的报告:
player first score points
foo 2010-05-20 19
bar 2010-04-15 29
baz 2010-02-04 13
现在,我的查询看起来像这样:
select p.name player,
min(s.date) first_score,
s.points points
from players p
join scores s on s.player_id = p.id
group by p.name, s.points
我需要与min(s.date)
返回的行关联的s.points
。这个查询会发生这种情况吗?也就是说,我如何确定我得到了正确的 s.points
连接行的值?
旁注:我想这在某种程度上与 mysql 缺乏密集排名有关。这里最好的解决方法是什么?
【问题讨论】:
【参考方案1】:这是 Stack Overflow 上经常出现的最大每组问题。
这是我通常的回答:
select
p.name player,
s.date first_score,
s.points points
from players p
join scores s
on s.player_id = p.id
left outer join scores s2
on s2.player_id = p.id
and s2.date < s.date
where
s2.player_id is null
;
换句话说,给定分数 s,尝试为同一玩家找到分数 s2,但日期更早。如果没有找到更早的分数,则 s 是最早的。
关于您对领带的评论:您必须制定一个政策,以在出现领带的情况下使用该政策。一种可能性是,如果您使用自动递增的主键,则具有最小值的主键是较早的主键。请参阅下面的外部连接中的附加术语:
select
p.name player,
s.date first_score,
s.points points
from players p
join scores s
on s.player_id = p.id
left outer join scores s2
on s2.player_id = p.id
and (s2.date < s.date or s2.date = s.date and s2.id < s.id)
where
s2.player_id is null
;
基本上,您需要添加决胜局条款,直到您找到一个保证唯一的列,至少对于给定的玩家而言。表的主键通常是最好的解决方案,但我见过其他列适合的情况。
关于我与@OMG Ponies 分享的 cmets,请记住,这种类型的查询极大地受益于正确的索引。
【讨论】:
+1:你有没有机会比较你和我的方法?我很好奇一个是否更有效,但我倾向于你的,因为 MySQL 如何处理 LEFT JOIN/IS NULL... 如果我的join scores s...
的连接条件比s.player_id = p.id
多,我是否也复制left outer join scores s2...
的所有这些条件?
@OMG Ponies:我发现在 MySQL 中使用 GROUP BY 是一个性能杀手,因为 MySQL 几乎总是创建一个临时表。而使用外连接解决方案(或等效的 NOT EXISTS 与相关子查询),可以使用覆盖索引,因此连接可以在内存中完成。
@macek:是的,连接到 s2 必须使用与连接到 s 相同的条件,加上比较日期的条件。如果您有平局的可能性(同一日期超过一个分数),您可能需要一个额外的加入期限来解决平局。
你完全正确!我为某些用户返回了多行,因为他们在玩的第一天就有大约 2-5 个分数。如何解决?【参考方案2】:
在使用 GROUP BY 时,大多数 RDMB 甚至不允许您在 SELECT 子句中包含非聚合列。在 MySQL 中,您最终会得到来自非聚合列的随机行的值。如果您在所有行的特定列中实际上具有相同的值,这将很有用。因此,很高兴 MySQL 没有限制我们,尽管理解这一点很重要。
SQL Antipatterns 中有一整章专门讨论这个问题。
【讨论】:
谢谢马库斯! :) 您还可以使用SET SQL_MODE = ONLY_FULL_GROUP_BY
使 MySQL 的行为更加标准
巧合的是,@Bill Karwin(作者是这个问题的公认答案)恰好是那本书的作者!小世界:)以上是关于从 MySQL 中的表中加入单行的主要内容,如果未能解决你的问题,请参考以下文章