为啥我可以从 NULL 列的左连接中选择一些东西?(用人为的例子在本地重现它,可能是一个错误!)

Posted

技术标签:

【中文标题】为啥我可以从 NULL 列的左连接中选择一些东西?(用人为的例子在本地重现它,可能是一个错误!)【英文标题】:Why can I select something out of left join on a NULL column?(with contrived example to reproduce it locally,probably a bug!)为什么我可以从 NULL 列的左连接中选择一些东西?(用人为的例子在本地重现它,可能是一个错误!) 【发布时间】:2009-10-04 15:15:02 【问题描述】:

版本 我正在使用服务器版本:5.1.36-community-log mysql Community Server (GPL)

我终于设计了一个简单的例子来轻松重现它!

设置:

create table t1(id integer unsigned,link integer unsigned);
create table t2(id integer unsigned auto_increment,primary key(id));
create table t3(id integer unsigned,content varchar(30));
insert into t1 value(1,null);
insert into t2 value(1);
insert into t3 value(1,'test');

然后运行:

select t2.*,t3.* 
from t1
left join t2 on t1.link=t2.id
left join t3 on t3.id=t2.id
where t1.id=1;

会弄错:

+------+------+---------+
| id   | id   | content |
+------+------+---------+
| NULL |    1 | test    |
+------+------+---------+

但如果我们以这种方式创建 t2,它就不会发生:

create table t2(id integer unsigned);

所以,它与主键有关!

新发现

运行这个不会触发bug:

select t2.*,t3.*
from t1
left join t2 on t1.link=t2.id
left join t3 on t2.id=t3.id
where t1.id=1;

所以它也与加入方向有关!

【问题讨论】:

其余的表是什么样子的? 连接是否有可能被优化?对查询运行解释以查看会发生什么... 请不要显示您的查询结果,而是向我们展示您所有的表格及其各自的内容! 我太兴奋了,不能成功地设计一个例子! 你有一个错字 - 你已经创建了 t2 两次。此外,为了一致性和可读性,与 t3 的连接最好写为 t2.id = t3.id,而不是相反(在我看来) 【参考方案1】:

我刚刚在 MySQL 5.0.58、5.0.82 和 5.1.35 上运行你创建、插入和选择,我收到了以下结果,我认为这是正确的:

+------+------+---------+
| id   | id   | content |
+------+------+---------+
| NULL | NULL | NULL    |
+------+------+---------+

这正是我使用的:

CREATE TABLE `t1` (
  `id` int(10) unsigned default NULL,
  `link` int(10) unsigned default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `t1` VALUES (1, NULL); 

CREATE TABLE `t2` (
  `id` int(10) unsigned NOT NULL auto_increment,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ;

INSERT INTO `t2` VALUES (1);

CREATE TABLE `t3` (
  `id` int(10) unsigned default NULL,
  `content` varchar(30) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `t3` VALUES (1, 'test');

SELECT t2.id, t3.id, t3.content
FROM t1
LEFT JOIN t2 ON t1.link = t2.id
LEFT JOIN t3 ON t2.id = t3.id
WHERE t1.id = 1;

【讨论】:

哦,那一定是服务器版本引入的bug:5.1.36-community-log MySQL Community Server (GPL) 我怀疑在 5.1.35 和 5.1.36 之间他们会引入那么大的错误。您是否确认您的 SQL 与您发布的内容(以及我发布的内容)相匹配? 太棒了!我进一步发现它是由连接方向引起的!请运行:select t2.*,t3.* from t1 left join t2 on t1.link=t2.id left join t3在 t3.id=t2.id 上 t1.id=1; 都不会为我产生错误。 你能在其他版本的 MySQL 上安装或测试吗?【参考方案2】:

'fuinfo' 中的'fid' 行之一是否设置为 NULL? MySQL 可能会将其与左表中的 NULL 值连接起来。

【讨论】:

但它没有设置为NULL,这里设置为“Tiger”! fuinfo.name 设置为“Tiger”,但它可能与 lefId 为 NULL 的答案中的一行配对。 但我已将连接条件指定为:ON f.id = a.lefId 是的,但是否有任何 f.id 字段设置为 NULL?我在想 MySQL 可以将 NULL 与 NULL 匹配。 不,只有一行,id为1。【参考方案3】:

非常有趣。这确实看起来像 MySQL 中的一个错误。查询结果取决于是否有主键。他们绝对不应该影响结果。作为参考,PostgreSQL 将返回带有主键的正确结果,所以我认为这不太可能是预期的行为。

【讨论】:

我可以因报告或发现错误而获得报酬吗?【参考方案4】:

您的设置代码错误

create table t1(id integer unsigned,link integer unsigned);  
create table t2(id integer unsigned auto_increment,primary key(id));  
create table t2(id integer unsigned,content varchar(30));

             ^^  This is wrong. Should be t3

另外,请确保在每次测试后放下表格。你可能有一些错误的数据。

【讨论】:

打错了,请在本地尝试一下,你肯定会遇到同样的问题! 它在 MSSQL 中运行正常,也许您应该在标题或正文中指定您的 DBMS,而不仅仅是标签。 我不喜欢被重复! Alex,通常只在标签中指定它。放在体内是个好主意,但绝对没有必要。

以上是关于为啥我可以从 NULL 列的左连接中选择一些东西?(用人为的例子在本地重现它,可能是一个错误!)的主要内容,如果未能解决你的问题,请参考以下文章

如何从访问数据库中的左连接中选择excel表 - EXCEL VBA

Hibernate - OneToMany 注释导致选择查询的左连接不匹配

为啥这个简单的左连接需要永远执行?

在 hive 中使用 Null 检查的左外连接查询不起作用

Linq中的左外连接

选择中的左连接与子查询的奇怪问题