带有 INSERT 和 WHERE NOT EXISTS 的奇怪 SQL 行为

Posted

技术标签:

【中文标题】带有 INSERT 和 WHERE NOT EXISTS 的奇怪 SQL 行为【英文标题】:Weird SQL behavior with INSERT and WHERE NOT EXISTS 【发布时间】:2011-06-10 15:59:26 【问题描述】:

我有这个查询,如果表中不存在相同 ID 的等于或更高的金额,它应该插入一个金额。

我在 mysql 5.1 和 MSSQL 2k5 下试过这个:

MySQL

INSERT IGNORE INTO 测试(ID、金额) 从测试中选择 6、50 WHERE NOT EXISTS (SELECT 1 from test WHERE amount >= 50 AND id = 6) LIMIT 1

MSSQL

INSERT INTO 测试(ID、金额) 从测试中选择 6、50 WHERE NOT EXISTS (SELECT TOP 1 1 FROM test WHERE amount >= 50 AND id = 6)

如果表中已经至少有一个条目,则此查询可以正常工作。如果表是空的,它将永远无法工作。在 MySQL (5.1) 和 MSSQL (2005) 下的行为相同。 我不明白为什么。即使表完全为空,任何人都有解释和方法来修复此查询以使其正常工作?

编辑:我主要需要这个用于 MySQL...

更新:我专门针对 MySQL 提出了一个新问题: MySQL Problem with inserting a row with certain conditions

【问题讨论】:

是 SELECT TOP 1 1 = SELECT TOP 1 * ? @Chris 我认为是这样,在“exists(select...”中我认为不需要顶部,也不需要 1。 我仍然无法让它在 MySQL 下工作......如果你有其他方法也可以。也许左连接可以工作? 【参考方案1】:

失败是因为 select 语句根据返回的行数选择了 6 和 50 的值。由于您的表是空的 - 不会返回任何具有这些值的行。

修改为

 INSERT INTO test (id, amount) SELECT 6, 50 WHERE NOT EXISTS (SELECT TOP 1 1 FROM test WHERE amount >= 50 AND id = 6) 

【讨论】:

它在 MySQL 中不起作用......它不喜欢 WHERE 之前没有 FROM 子句:( 在 MySQL 下不起作用。不能缺少 FROM 子句,如果添加它,在没有行的情况下仍然是同样的问题... 我接受了它,因为它在 MSSQL 下工作,而我对 MySQL 不够精确。我为 MySQL 提出了一个新问题,请在我的帖子中查看更新以获取链接。谢谢:) 似乎倒退了“编辑:我主要需要这个用于 MySQL...” 如果添加“FROM DUAL”,它可以在 MySQL 上运行 - DUAL 显然就像一个虚拟表,它总是像只有一行一样。【参考方案2】:

如下更改您的查询:

INSERT INTO test (id, amount) 
SELECT 6, 50 FROM test 
WHERE (SELECT count(*) FROM test WHERE amount >= 50 AND id = 6) = 0 

【讨论】:

当表为空时影响 0 行:|当表格中至少有一行时工作......奇怪的胡:P 这不像预期的那样工作,我已经测试并得到了另一个解决方案【参考方案3】:

我一步一步尝试了这个:

    -- create a test-table with one entry
SELECT id = 1, amount = 50 
into #TEST

-- see if statement works when table is not empty
INSERT INTO #test (id, amount)  
SELECT id = 6, amount = 50 
FROM #test  
WHERE NOT EXISTS (SELECT * FROM #test WHERE amount >= 50 AND id = 6) 

-- show content of test-table
select * from #test

-- empty the test table
truncate table #test

-- try to insert a first dataentry
INSERT INTO #test (id, amount)  
SELECT id = 6, amount = 50 
FROM #test  
WHERE NOT EXISTS (SELECT * FROM #test WHERE amount >= 50 AND id = 6) 
union
SELECT id = 6, amount = 50 
where (SELECT C = COUNT(*)  FROM #test WHERE amount >= 50 AND id = 6) = 0

-- show content of test-table
select * from #test

-- remove Test-table
drop table #test

首先,我尝试重现该行为,是的,这很奇怪。工会 - think 管理空表案例,瞧,这工作正常。

【讨论】:

再一次,它似乎不适用于 MySQL。 SELECT id = 6, amount = 50 不起作用,MySQL 似乎需要一个“FROM”子句。 :(【参考方案4】:

好的,这才是真正的问题。试试这个,使用第二个表(#test2):

    -- create a test-table with one entry
SELECT id = 1, amount = 50 
into #TEST

-- create a second test-table with one entry
SELECT id = 1, amount = 50 
into #TEST2

-- see if statement works when table is not empty
INSERT INTO #test (id, amount)  
SELECT id = 6, amount = 50 
FROM #test  
WHERE NOT EXISTS (SELECT * FROM #test WHERE amount >= 50 AND id = 6) 

-- show content of test-table
select * from #test

-- empty the test table
truncate table #test

INSERT INTO #test (id, amount) SELECT 6, 50 WHERE NOT EXISTS (SELECT TOP 1 1 FROM #test WHERE amount >= 50 AND id = 6)  

-- try to insert a first dataentry
INSERT INTO #test (id, amount)  
SELECT id = 6, amount = 50 
FROM #test  
WHERE NOT EXISTS (SELECT * FROM #test WHERE amount >= 50 AND id = 6) 
union
SELECT id = 6, amount = 50 
from #test2
where (SELECT C = COUNT(*)  FROM #test) = 0


-- show content of test-table
select * from #test

-- remove Test-table
drop table #test

(假设您知道前面有 # 的表,这是 MS-SQL 中的临时表)。

BonyT 已经解释了原因。

【讨论】:

在 MYSQL 下试过这个:INSERT INTO test (id, amount) SELECT id = 6, amount = 50 FROM test WHERE NOT EXISTS (SELECT * FROM test WHERE amount >= 50 AND id = 6) UNION SELECT id = 6, amount = 50 FROM test2 WHERE (SELECT COUNT(*) AS C FROM test) = 0 还是同样的问题?

以上是关于带有 INSERT 和 WHERE NOT EXISTS 的奇怪 SQL 行为的主要内容,如果未能解决你的问题,请参考以下文章

带有插入语句的 Where 子句

INSERT INTO WITH SELECT 和 WHERE(问题)

insert into 和 where not exists

MS-Access:SQL JOIN 和 INSERT INTO 与 WHERE 慢

sql - mybatis的动态字段insert和IFNULL结合where使用实践

为啥我不能在 INSERT 语句中使用 WHERE 子句进一步压缩我的查询?