奇怪的MySQL行为,似乎是一个SQL bug

时间:2010-06-01 21:29:09

标签: mysql

我在MySQL中遇到了一种非常奇怪的行为,这看起来像某种奇怪的错误。我知道将这个经过试验和测试的工具归咎于一个人的错误是很常见的,但我已经讨论了一段时间了。

我有2个表,我有2797个记录,C有1429个.C引用I.
我想删除I中没有被C使用的所有记录,所以我正在做:

select * from i where id not in (select id_i from c);

返回0条记录,鉴于每张表中的记录数,实际上是不可能的。我也非常确定查询是正确的,因为它与我在过去2小时内使用的查询类型相同,以清理其他具有孤立记录的表。

让事情变得更奇怪......

select * from i where id in (select id_i from c);

是否有效,并带给我1297条我不想删除的记录 所以,IN有效,但不是IN。

更糟糕的是:

select * from i where id not in (
  select i.id from i inner join c ON i.id = c.id_i
);

那可行,虽然它应该等同于第一个查询(我现在只是尝试疯狂的东西)。
唉,我不能使用这个查询来删除,因为我正在使用我在子查询中删除的同一个表。

我假设我的数据库中某些此时已损坏。

如果重要的话,这些都是MyISAM表,没有任何外键,无论如何,我在我的开发机器和生产服务器中运行相同的查询,结果相同,所以无论腐败如何,都可能存活下来mysqldump / source cycle,听起来很奇怪。

关于可能出现什么问题的任何想法,或者更重要的是,我如何解决/解决这个问题?

谢谢!
丹尼尔

3 个答案:

答案 0 :(得分:9)

我猜你有一行包含NULL值。 INNOT IN的行为方式可能会在您有NULL值时出现。来自manual

  

为了符合SQL标准,IN不仅在左侧的表达式为NULL时返回NULL,而且如果在列表中找不到匹配且列表中的一个表达式为NULL,则返回NULL。

NOT NULL的值仍为NULL,并非如您所愿。

以下是一个简化示例的行为演示:

CREATE TABLE c (id_i INT NULL);
INSERT INTO c (id_i) VALUES
(1),
(2),
(NULL);

CREATE TABLE i (id INT NOT NULL);
INSERT INTO i (id) VALUES
(1),
(2),
(3);

SELECT * FROM i WHERE id NOT IN (SELECT id_i FROM c); -- returns nothing
SELECT * FROM i WHERE id IN (SELECT id_i FROM c);     -- returns 1,2
SELECT * FROM i WHERE id NOT IN (                     -- returns 3
  SELECT i.id FROM i INNER JOIN c ON i.id = c.id_i
);

答案 1 :(得分:2)

  

我想删除I中未被C

使用的所有记录

对于它的价值,MySQL支持对多表DELETE语法的标准SQL的扩展,您可以使用它来绕过NOT IN谓词和NULL以及子查询中的特性。

DELETE I
FROM I LEFT OUTER JOIN C ON (i.id = c.id_i)
WHERE c.id_i IS NULL;

注意:我没有测试过,只是来自内存。请自己阅读manual并在一些示例数据上进行测试,以确保它在您在真实数据库中使用之前按预期工作。

答案 2 :(得分:1)

如果您尝试此查询,会得到什么?

select * 
  from i 
 where NOT EXISTS (select id_i 
                     from c
                    where c.id_i = i.id
                  )