我想在MySQL中进行完全的外部连接。这可能吗?MySQL是否支持完全外部联接?
当前回答
使用交叉联接解决方案:
SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2
ON 1=1;
其他回答
为了更清晰,我修改了shA.t的查询:
-- t1 left join t2
SELECT t1.value, t2.value
FROM t1 LEFT JOIN t2 ON t1.value = t2.value
UNION ALL -- include duplicates
-- t1 right exclude join t2 (records found only in t2)
SELECT t1.value, t2.value
FROM t1 RIGHT JOIN t2 ON t1.value = t2.value
WHERE t1.value IS NULL
前面的答案实际上都不正确,因为当存在重复值时,它们不遵循语义。
对于查询,例如(来自此副本):
SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.Name = t2.Name;
正确的等效值为:
SELECT t1.*, t2.*
FROM (SELECT name FROM t1 UNION -- This is intentionally UNION to remove duplicates
SELECT name FROM t2
) n LEFT JOIN
t1
ON t1.name = n.name LEFT JOIN
t2
ON t2.name = n.name;
如果需要使用NULL值(这可能也是必要的),则使用NULL安全比较运算符<=>而不是=。
MySQL没有FULL-OUTER-JOIN语法。您必须通过如下方式执行LEFT JOIN和RIGHT JOIN来模拟它:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
但MySQL也没有RIGHT JOIN语法。根据MySQL的外部连接简化,通过切换查询中FROM和ON子句中的t1和t2,将右连接转换为等效的左连接。因此,MySQL查询优化器将原始查询转换为以下内容-
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
现在,按原样编写原始查询是没有害处的,但是如果您有WHERE子句之类的谓词,这是一个预连接谓词,或者on子句上的AND谓词,它是一个在连接期间的谓词,那么您可能需要看看魔鬼;这是详细的。
MySQL查询优化器定期检查谓词是否被null拒绝。
现在,如果您已经执行了RIGHT JOIN,但在t1开始的列上使用了WHERE谓词,那么您可能会遇到空拒绝的情况。
例如,查询
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
由查询优化器转换为以下内容:
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
WHERE t1.col1 = 'someValue'
因此,表的顺序已经改变,但谓词仍然应用于t1,但t1现在位于“ON”子句中。如果t1.col1定义为NOT NULL列,则此查询将被null拒绝。
任何被null拒绝的外部联接(左、右、全)都会被MySQL转换为内部联接。
因此,您可能期望的结果可能与MySQL返回的结果完全不同。您可能会认为MySQL的RIGHT JOIN存在缺陷,但这是不对的。这就是MySQL查询优化器的工作方式。因此,负责开发人员在构建查询时必须注意这些细微差别。
我修复了响应,工作包括所有行(基于Pavle Lekic的响应):
(
SELECT a.* FROM tablea a
LEFT JOIN tableb b ON a.`key` = b.key
WHERE b.`key` is null
)
UNION ALL
(
SELECT a.* FROM tablea a
LEFT JOIN tableb b ON a.`key` = b.key
where a.`key` = b.`key`
)
UNION ALL
(
SELECT b.* FROM tablea a
right JOIN tableb b ON b.`key` = a.key
WHERE a.`key` is null
);
使用交叉联接解决方案:
SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2
ON 1=1;
推荐文章
- 如何使用SQL Server 2008做多个CASE WHEN条件?
- 计数在VARCHAR字段中字符串的出现次数?
- 如何选择多行填充常量?
- 修改一个MySQL列为AUTO_INCREMENT
- 如果没有使用EXISTS引入子查询,则只能在选择列表中指定一个表达式
- SQL Server -事务回滚错误?
- 如何在SQL中有效地计数列值的发生?
- PostgreSQL列名区分大小写吗?
- 在WHERE子句中引用列别名
- 在ROR迁移期间,将列类型从Date更改为DateTime
- 恢复未保存的SQL查询脚本
- 如何删除所有MySQL表从命令行没有DROP数据库权限?
- 从主机连接到docker容器中的mysql
- 如果任何字段包含NULL, MySQL CONCAT将返回NULL
- 向临时表中插入数据