2011-11-09 69 views
0

我试图更新行,如果它存在,否则插入(在重复键更新)在MS Access,与答案来自这个问题SQL access query- Update row if exists, insert if does not与NOT IN子查询

我插入查询插入语句的形式为:

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

但我得到一个SQL语法错误。我在这里错过了什么?

+2

你愿意和我们分享这个错误? – zmilojko

+0

只是“INSERT INTO语句中的语法错误” – Christine

+1

这可能是围绕SELECT的括号。 – zmilojko

回答

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来实现同样的目的。不过,我认为性能会更差,除非数据库引擎足够聪明才能认识到每行都是相同的。

编辑:DummyTableWithExactlyOneRecord是一个只有一条记录的本地表。正如@onedaywhen在他的评论中指出的那样,如果表格中没有任何记录,那么您将不会插入任何记录。

请注意,如果您可以保证您的虚拟表格总是只有1条记录,那么TOP 1条款不是必需的。不过,我已经把它留了下来,因为我认为这让读者不知道虚拟表格的内容(我假设你将命名虚拟表格的内容比DummyTableWithExactlyOneRecord短)。

+0

现在我得到一个重复键错误,即使10真的不在mytbl中。但至少语法错误是固定的,谢谢! – Christine

+1

您正在获取重复键错误,因为如果10不是表中的ID值,则SELECT ... WHERE 10 Not IN(...)'返回每行“mytbl”的结果。 – mwolfe02

+0

啊,这很有道理。在TOP 1放入SELECT子句后,它现在正确插入。感谢您的帮助,这让我疯狂。 – Christine

0

我想ü正在寻找ID,而不是10

试试这个

WHERE id NOT IN (SELECT id FROM mytbl

+1

我试图插入一个值到ID如果该值不是在mytbl,所以我很确定我需要为NOT IN运算符指定一些值... – Christine

0

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

你有没有考虑下面的SQL:

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

如果这是对于通过填充表与SQL传递一种形式的伪代码:

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

通常是恒定值,使用插入或者沿着这些线路,可能会更容易地捕获PK违例的错误代码并将错误报告给用户。

希望这会有所帮助。

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';