Why does this simple Left Join return data from unmatched rows?
有关操作中的此问题,请参见简单的http://sqlfiddle.com/#!9/e853f/1。
我指的是MySQL ver 5.6.12-log
据我所知,左连接对最右边数据集中的列返回NULL,而在右边数据集中不存在左数据集中的键。
但是,即使右边没有左键,我也会从右侧获得数据。
任何人都可以解释这里发生了什么吗?
SQLfiddle创建:
- 具有6行的表,每行仅包含一个整数ID
-
第二张表包含3行,其中包含一些整数ID加2
更多INT字段 - 基于第二个表的视图,该表返回3行,其中包含整数ID以及从其他两个INT字段派生的文本字段
(显然,视图中的3个ID对应于6行表中的某些ID。)
SQL
SELECT * FROM LEFT JOIN ON table_ID = view_ID;
返回预期的6行,但所有行均在文本字段中具有数据,而不是3个不匹配的行为NULL
但是
如果视图中用于派生文本列的方法稍有更改,则"左联接SQL"将给出正确的结果。
(您可以通过在sql小提琴中有选择地注释掉两种方法中的一种或另一种来显示此内容)
但是,优化器当然不会首先评估视图,因此,如何创建数据以及包含的内容都无关紧要?
(这是我先前提出的一个问题的简化版本,我承认这个问题对于非法的明智答案而言过于复杂)。
有人建议(Jeroen Mostert)显示数据和预期结果。它是:
餐桌人物
1 2 3 4 5 6 7 8 | personID -------- 1 2 3 4 5 6 |
查看付款状态
1 2 3 4 5 | payment_personID | state ---------------------------- 1 | 'equal' 2 | 'under' 3 | 'over' |
查询
预期结果
1 2 3 4 5 6 7 8 |
实际结果
1 2 3 4 5 6 7 8 |
我不同意其他答案。这是MySQL的缺陷。实际上,这是MySQL 5.6中的错误#83707。看起来它已在MySQL 5.7
中修复
此错误已在MariaDB 5.5中修复。
内部联接策略(例如嵌套循环联接,合并联接或哈希联接)无关紧要。在任何情况下,结果都应该正确。
我在PostgreSQL和Oracle中尝试了相同的查询,它按预期工作,在最后三行返回空值。
Oracle示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | CREATE TABLE person (personID INT); INSERT INTO person (personID) VALUES (1); INSERT INTO person (personID) VALUES(2); INSERT INTO person (personID) VALUES(3); INSERT INTO person (personID) VALUES(4); INSERT INTO person (personID) VALUES(5); INSERT INTO person (personID) VALUES(6); CREATE TABLE payments ( payment_personID INT, Due INT, Paid INT) ; INSERT INTO payments (payment_personID, due, paid) VALUES (1, 5, 5); INSERT INTO payments (payment_personID, due, paid) VALUES (2, 5, 3); INSERT INTO payments (payment_personID, due, paid) VALUES (3, 5, 8); CREATE VIEW payment_state AS ( SELECT payment_personID, CASE WHEN COALESCE(paid,0) < COALESCE(due,0) AND due <> 0 THEN 'under' WHEN COALESCE(paid,0) > COALESCE(due,0) THEN 'over' WHEN COALESCE(paid,0) = COALESCE(due,0) THEN 'equal' END AS state FROM payments); SELECT * FROM person LEFT JOIN payment_state ON personID = payment_personID; |
结果:
1 2 3 4 5 6 7 8 | PERSONID PAYMENT_PERSONID STATE ======== ================ ===== 1 1 equal 2 2 under 3 3 over 6 <null> <null> 5 <null> <null> 4 <null> <null> |
完美运行!
PostgreSQL示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | CREATE TABLE person (personID INT); INSERT INTO person (personID) VALUES (1),(2),(3),(4),(5),(6); CREATE TABLE payments ( payment_personID INT, Due INT, Paid INT) ; INSERT INTO payments (payment_personID, due, paid) VALUES (1, 5, 5), (2, 5, 3), (3, 5, 8); CREATE VIEW payment_state AS ( SELECT payment_personID, CASE WHEN COALESCE(paid,0) < COALESCE(due,0) AND due <> 0 THEN 'under' WHEN COALESCE(paid,0) > COALESCE(due,0) THEN 'over' WHEN COALESCE(paid,0) = COALESCE(due,0) THEN 'equal' END AS state FROM payments); SELECT * FROM person LEFT JOIN payment_state ON personID = payment_personID; |
结果:
1 2 3 4 5 6 7 8 | personid payment_personid state ======== ================ ===== 1 1 equal 2 2 under 3 3 over 4 <null> <null> 5 <null> <null> 6 <null> <null> |
也很完美!
您的视图的处理算法会导致此结果。默认情况下,MySQL通常选择MERGE,因为它效率更高。如果使用" TEMPTABLE"算法创建视图,则对于不匹配的行,您将看到NULL。
http://www.mysqltutorial.org/create-sql-views-mysql.aspx
1 2 3 4 5 6 7 8 9 |
这是
-
如果
JOIN 成功,则从要JOIN 的表中提取的值, -
如果
JOIN 不匹配,则为NULL s(包括您加入的ON 字段)!
通常,从真实表(匹配
事实上,如果您想知道您正在查看的给定