请注意操作中此问题的简单http://sqlfiddle.com/#!9/e853f/1。
我指的是MySQL ver 5.6.12-log
根据我的理解,左连接为最右边数据集中的列返回NULL,其中左侧数据集中的键不存在于右侧数据集中。
但是,即使右手边没有左手键,我也会从右侧返回数据。
有谁能解释这里发生了什么?
SQLfiddle创建:
(显然,视图中的3个ID对应于6行表中的某些ID。)
SQL SELECT * FROM LEFT JOIN on table_ID = view_ID; 按预期返回6行,但所有在文本字段中有数据,而不是3个不匹配的数据为NULL
BUT
如果视图中用于派生文本列的方法稍有改动,那么Left Join SQL会给出正确的结果。 (您可以通过选择性地在sql小提琴中注释掉这两种方法中的一种或其他方式来显示这一点)
但是,优化者肯定不会首先评估视图,因此创建数据的方式并不重要,只是它包含的内容是什么?
(这是我早先提出的一个问题的简化版本,我承认这个版本太复杂了,不合理的答案)
有人建议(Jeroen Mostert)我会显示数据和预期结果。这是:
表人
personID
--------
1
2
3
4
5
6
查看payment_state
payment_personID | state
----------------------------
1 | 'equal'
2 | 'under'
3 | 'over'
查询
SELECT * FROM person
LEFT JOIN payment_state
ON personID = payment_personID;
预期结果
personID | payment_personID |state
-------------------------------------
1 | 1 | 'equal'
2 | 2 | 'under'
3 | 3 | 'over'
4 | NULL | NULL
5 | NULL | NULL
6 | NULL | NULL
实际结果
personID | payment_personID |state
-------------------------------------
1 | 1 | 'equal'
2 | 2 | 'under'
3 | 3 | 'over'
4 | NULL | 'equal'
5 | NULL | 'equal'
6 | NULL | 'equal'
答案 0 :(得分:2)
我不同意其他答案。 这是一个MySQL缺陷。实际上它是MySQL 5.6中的bug #83707。它看起来已经在MySQL 5.7中修复了
此错误已在MariaDB 5.5中修复。
内部连接策略(如嵌套循环连接,合并连接或散列连接)无关紧要。无论如何,结果应该是正确的。
我在PostgreSQL和Oracle中尝试了相同的查询,它按预期工作,在最后三行返回空值。
Oracle示例
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;
结果:
PERSONID PAYMENT_PERSONID STATE
======== ================ =====
1 1 equal
2 2 under
3 3 over
6 <null> <null>
5 <null> <null>
4 <null> <null>
完美无缺!
PostgreSQL示例
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;
结果:
personid payment_personid state
======== ================ =====
1 1 equal
2 2 under
3 3 over
4 <null> <null>
5 <null> <null>
6 <null> <null>
另外,效果很好!
答案 1 :(得分:1)
视图的处理算法会导致此结果。默认情况下,MySQL通常会选择MERGE,因为它更有效。如果使用“TEMPTABLE”算法创建视图,则可以看到不匹配行的NULL。
http://www.mysqltutorial.org/create-sql-views-mysql.aspx
CREATE ALGORITHM = TEMPTABLE VIEW payment_state AS (
SELECT
payment_personID,
CASE
WHEN IFNULL(paid,0) < IFNULL(due,0) AND due <> 0 THEN 'under'
WHEN IFNULL(paid,0) > IFNULL(due,0) THEN 'over'
WHEN IFNULL(paid,0) = IFNULL(due,0) THEN 'equal'
END AS state
FROM payments);
答案 2 :(得分:0)
这是LEFT JOIN
正常工作的方式。它会在结果中附加新列,然后用以下内容填充:
JOIN
成功,则JOIN
表中提取的值NULL
不匹配(包括您加入的字段JOIN
),则ON
!通常情况下,NULL
从真实表格(其中JOIN
匹配)和NULL
填充的JOIN
之间没有区别,因为CASE
不匹配。 IFNULL
+ NULL
只需查找0
并将其转换为NULL
s(无论其来源)。这就是为什么即使在不匹配的行中也会在 state 列中生成结果。
事实上,如果您想知道您所查看的某个JOIN
是否与JOIN
不匹配,您需要明确检查这一点 - 如果所有关键字段都是如此如果此列中的NULL
是填写的结果,则NULL
的{{1}}为NULL
。如果此行中存在来自键的字段,但其他列中仍有JOIN
,那么它就在那里,因为它是从您SELECT DISTINCT COUNT(*) OVER () AS TotalRecords
FROM table
GROUP BY column
编辑的表格中提取的。