使用NOT IN子查询插入语句

时间:2011-11-09 20:03:07

标签: sql ms-access

我正在尝试更新一行(如果存在),否则在MS Access中插入(在重复键更新时),并回答此问题SQL access query- Update row if exists, insert if does not

我的插入查询的格式为:

INSERT INTO mytbl(id, title, notes) 
(SELECT 10, 'test', 'a'
From mytbl
WHERE 10 Not IN (select id from mytbl)
)

但是我收到了SQL语法错误。我在这里缺少什么?

4 个答案:

答案 0 :(得分:2)

你不需要外围的SELECT括号:

INSERT INTO mytbl(id, title, notes) 
SELECT TOP 1 10, 'test', 'a'
FROM DummyTableWithExactlyOneRecord
WHERE 10 Not IN (select id from mytbl)

为了处理重复键错误,我添加了TOP 1子句。

最初编写查询的方式,如果10不是mytbl中的ID,则查询的SELECT部分​​将返回mytbl中每个现有行的记录。因为您没有引用表中的任何字段,所以它们都是相同的行。例如,如果mytbl中有四行,您将拥有:

10    test    a
10    test    a
10    test    a
10    test    a

然后尝试为每个返回的行执行插入操作。第一个会成功,其余的会因重复键错误而失败。 TOP 1子句表示只使用TOP 1记录。在这种情况下,顺序无关紧要。由于您的所有字段都是文字,因此每一行都是相同的。

请注意,您可以通过将DISTINCT替换为TOP 1来完成同样的事情。不过,我希望性能会更差,除非db引擎足够聪明,能够预先确认每一行都是相同的。

编辑:DummyTableWithExactlyOneRecord是一个只有一条记录的本地表。正如@onedaywhen在下面的评论中指出的那样,如果您正在选择的表中根本没有记录,则不会插入任何记录。

请注意,如果您可以保证虚拟表始终只有1条记录,则不需要TOP 1子句。但是,我已将其留在原因,因为我认为它使得意图对于可能不知道虚拟表格内容的读者来说更明显(我假设您将命名您的虚拟表格比{更短的内容] {1}})。

答案 1 :(得分:0)

我想你正在寻找ID而不是10

试试这个

WHERE id NOT IN (SELECT id FROM mytbl

答案 2 :(得分:0)

这里有趣的是,您尝试将常量值插入表中,同时还验证UNIQUE INDEX(或PK)尚不存在。因此,您的WHERE子句必须以这样的方式构造,即它产生一个FALSE条件,因此不会生成要插入的行。

您是否考虑过以下SQL:

INSERT INTO mytbl(id, title, notes) 
SELECT 10, 'test', 'a'
From mytbl
WHERE id NOT IN (SELECT id FROM mytbl WHERE id = 10)

通常使用以下函数插入常量值:

INSERT INTO mytbl(id, title, notes) VALUES (10, 'test', 'a');

如果这是用于填充带有SQL Pass Through的表格的表格的伪代码或沿着这些行的某些内容,则可能更容易捕获PK违规的错误代码并将错误报告给用户。

希望这有帮助。

答案 3 :(得分:0)

SQL DDL

CREATE PROCEDURE AddMyStuff 
(
 :id CHAR(10), 
 :title VARCHAR(15), 
 :notes VARCHAR(100) = '{{NONE}}'
)
AS
INSERT INTO mytbl (id, title, notes) 
SELECT :id, :title, :notes
  FROM MySystemTableAlwaysHasExactlyOneRow
 WHERE :id NOT IN (SELECT id FROM mytbl);

SQL DML

EXECUTE AddMyStuff 10, 'test', 'a';