【问题标题】:MySQL left join excludes non-matching records?MySQL左连接排除不匹配的记录?
【发布时间】:2015-07-08 19:58:34
【问题描述】:

当我执行这个 MySQL 查询时,我得到了预期的正确结果:

select h.ID AS ProductID, h.ProductTitle, u.Username, ht.ProductType, hd.Difficulty-- , ifnull(sum(pv.UpVote),0) - ifnull(sum(pv.DownVote),0) AS NetVotes
from Products h 
join Users u on h.UserID = u.ID 
join ProductTypes ht on h.ProductTypeID = ht.ID 
join ProductDifficulties hd 
on h.ProductDifficultyID = hd.ID 
-- left join ProductVotes pv
-- on h.ID = pv.ProductID

请注意,我注释掉了选择(聚合)和左连接中的最后一列。但是当我在 sql 中包含所有内容时,只会包含具有匹配 ProductVotes 记录的记录:

select h.ID AS ProductID, h.ProductTitle, u.Username, ht.ProductType, hd.Difficulty, ifnull(sum(pv.UpVote),0) - ifnull(sum(pv.DownVote),0) AS NetVotes
from Products h 
join Users u on h.UserID = u.ID 
join ProductTypes ht on h.ProductTypeID = ht.ID 
join ProductDifficulties hd 
on h.ProductDifficultyID = hd.ID 
left join ProductVotes pv
on h.ID = pv.ProductID

我希望这种行为来自内部联接,而不是左联接。为什么左连接会排除没有匹配 ProductVotes 记录的记录?我怎样才能将这些包括在内,就像上面的第一个查询一样?

编辑:最初我在查询末尾有一个LIMIT 0, 10,有些人认为这是导致问题的原因。我删除了限制条款,问题仍然存在,因此与它无关。现在我从我的原始帖子中删除了LIMIT 子句,因为它无关紧要。仍在等待答案。 :-)

这是select * from ProductVotes的完整结果:

ID ProductID UserID UpVote DownVote
 2         1      2      1 NULL
 3         1      3      1 NULL
 4         1      4      1 NULL
 5         1      5      1 NULL
 6         1      6      1 NULL
 7         1      7      1 NULL
 8         1      8      1 NULL
 9         1      9   NULL    1
10         1     10   NULL    1
22         1      1      1 NULL

(请注意表中只有 10 条记录。)

重要提示:请注意我的选择语句中的聚合:ifnull(sum(pv.UpVote),0) - ifnull(sum(pv.DownVote),0) AS NetVotes

【问题讨论】:

  • 可以取消限制吗?您将看到所有匹配和不匹配的行。
  • 不可能。你是否缩短了陈述?第二条语句不能返回少于 1 条语句的行
  • 不分投票表中有多少行。即使它是空的,第二条语句也不能产生比第一条语句少的行。你确定你没有在某处过滤结果吗?
  • 第二个查询正好返回 1 行,它是 ProductID 为 1 的行。它的行为就像一个内部连接。我以前从未见过这种情况,我使用 MySQL 已经 12 年了。我很困惑。
  • 内连接会返回 10 行 :) 因为投票表中有 10 个 id 为 1 的产品。

标签: mysql left-join


【解决方案1】:
select h.ID AS ProductID, h.ProductTitle, u.Username, ht.ProductType, hd.Difficulty, 
(select ifnull(sum(pv.UpVote),0) - ifnull(sum(pv.DownVote),0) from ProductVotes pv where h.ID = pv.ProductID ) AS NetVotes
from Products h 
join Users u on h.UserID = u.ID 
join ProductTypes ht on h.ProductTypeID = ht.ID 
join ProductDifficulties hd 
on h.ProductDifficultyID = hd.ID

【讨论】:

  • 限制是我的网格分页工作所必需的。而且我不明白这怎么可能是问题所在。我的查询 #1 带回 6 条记录,这是正确的。我的查询 #2 只带回 1 条记录,因为正在过滤不匹配的行。两个查询都没有达到 10 条记录的限制。
  • 不可能。你没有向我们展示重要的东西
  • 感谢您的坚持,乔治!效果很好。
  • 抱歉,恕我直言,这是一个糟糕的要求。一旦你有更多的数据,它会很快减速。
【解决方案2】:

你的问题不是LEFT JOIN,而是LIMIT 0,10

因此,要修复它,您可以从查询中删除 LIMIT

或者您可以尝试将LEFT JOINed 记录放在底部的方式更改顺序,例如:

SELECT 
  h.ID AS ProductID, 
  h.ProductTitle, 
  u.Username, 
  ht.ProductType, 
  hd.Difficulty, 
  hv.NetVotes
FROM Products h 
LEFT JOIN Users u 
ON h.UserID = u.ID 
LEFT JOIN ProductTypes ht 
ON h.ProductTypeID = ht.ID 
LEFT JOIN ProductDifficulties hd 
ON h.ProductDifficultyID = hd.ID 
LEFT JOIN (
   SELECT
      ProductID,
      SUM(IFNULL(UpVote,0) - IFNULL(hv.DownVote,0)) AS NetVotes
   FROM
      ProductVotes
   GROUP BY ProductID
) hv
ON h.ID = hv.ProductID
LIMIT 0, 10;

【讨论】:

  • 限制是我的网格分页工作所必需的。而且我不明白这怎么可能是问题所在。我的查询 #1 带回 6 条记录,这是正确的。我的查询 #2 只带回 1 条记录,因为正在过滤不匹配的行。两个查询都没有达到 10 条记录的限制。
  • 另外,这并没有改变任何东西:ORDER BY IF(hv.ProductID IS NULL,0,1) ASC
  • 请发布您的数据样本以继续讨论
  • 你知道 sqlfiddle sqlfiddle.com 吗?我们需要你所有的表格数据样本
  • @SweatCoder 检查更新的查询。但我仍然需要数据样本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-15
  • 1970-01-01
  • 1970-01-01
  • 2015-09-09
相关资源
最近更新 更多