SQL - 如果存在则更新,否则插入语法错误

33

我有以下的SQL查询:

IF EXISTS(SELECT * FROM component_psar WHERE tbl_id = '2' AND row_nr = '1') 
   UPDATE component_psar
      SET col_1 = '1', col_2 = '1', col_3 = '1', col_4 = '1', col_5 = '1',
                 col_6 = '1', unit = '1', add_info = '1', fsar_lock = '1' 
    WHERE tbl_id = '2' AND row_nr = '1' 
ELSE 
    INSERT INTO component_psar (tbl_id, row_nr, col_1, col_2, col_3, col_4,
                                col_5, col_6, unit, add_info, fsar_lock)
    VALUES ('2', '1', '1', '1', '1', '1', '1', '1', '1', '1', 'N')

忽略我试图将每一列都设置为'1'的事实,这只是示例数据。 :)

无论如何,执行此查询会返回语法错误:

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your
     MySQL server version for the right syntax to use near 'IF EXISTS(SELECT * FROM
     component_psar WHERE tbl_id = '2' AND row_nr = '1') UP' at line 1

我已经盯着这个问题看了半小时并在互联网上搜索,但就是找不出这个所谓的语法错误。可能最后会发现是我漏掉了一些非常愚蠢的东西,因此我需要你们的帮助。


你是在执行存储过程吗? - juergen d
不,我没有将它作为存储过程执行。我应该这样做吗? - AdamLazaruso
可能是将数据插入MySQL表中,如果存在则更新的重复问题。 - Jim Fell
IF EXISTS语法仅适用于MSSQL,不适用于MySQL。 - jasie
6个回答

61
INSERT INTO component_psar (tbl_id, row_nr, col_1, col_2, col_3, col_4, col_5, col_6, unit, add_info, fsar_lock)
VALUES('2', '1', '1', '1', '1', '1', '1', '1', '1', '1', 'N')
ON DUPLICATE KEY UPDATE col_1 = VALUES(col_1), col_2 = VALUES(col_2), col_3 = VALUES(col_3), col_4 = VALUES(col_4), col_5 = VALUES(col_5), col_6 = VALUES(col_6), unit = VALUES(unit), add_info = VALUES(add_info), fsar_lock = VALUES(fsar_lock)

可以与具有UNIQUE键的tbl_idrow_nr配合使用。

这是DocJonas链接并提供示例的方法。


1
这个很好用,谢谢。我不得不将tbl_id和row_nr设置为唯一键才能使其工作,但事后看来它们本来就应该是唯一的,所以这只是另一件做对了的事情。 :) - AdamLazaruso
很好指出UNIQUE列与PRIMARY的作用方式相同。我不确定它是否会引起问题。 - The Thirsty Ape
你如何知道它是插入还是更新,以便进行后续操作? - Alfonso Fernandez-Ocampo
1
使用ON DUPLICATE KEY UPDATE,每行受影响的行数为1,如果该行被插入为新行,则为1,如果现有行已更新,则为2。 - Robin Castlin
我在插入和更新一个大表(150-200k行)时遇到了麻烦,使用“插入更新重复项”功能速度更快(每1000行5秒 vs 60秒)。 - Dennis Heiden
只有当“tbl_id”和“row_nr”两者都存在时,它才能正常工作,否则插入操作将无法执行。 - Samir

13

我很感激你的好意(以及一开始给我的回答),但是像Robin Castlin那样向我展示如何点火的例子比告诉我在Google上搜索“如何生火”更有用。 :) - AdamLazaruso
虽然那是真的,但我个人最喜欢通过例子来学习。希望这足以让他知道如何在将来使用该函数。 - Robin Castlin

6
你需要添加THEN
IF EXISTS(SELECT * FROM component_psar WHERE tbl_id = '2' AND row_nr = '1') 
THEN
UPDATE component_psar SET col_1 = '1', col_2 = '1', col_3 = '1', col_4 = '1', col_5 = '1', col_6 = '1', unit = '1', add_info = '1', fsar_lock = '1' WHERE tbl_id = '2' AND row_nr = '1' 
ELSE 
INSERT INTO component_psar (tbl_id, row_nr, col_1, col_2, col_3, col_4, col_5, col_6, unit, add_info, fsar_lock) VALUES('2', '1', '1', '1', '1', '1', '1', '1', '1', '1', 'N')

2
是否有替代MySQL的选择? - Jerry

3

这种方法只有在更新成功时才会执行一次语句。

-- For each row in source
BEGIN TRAN    

UPDATE target
SET <target_columns> = <source_values>
WHERE <target_expression>

IF (@@ROWCOUNT = 0)
   INSERT target (<target_columns>)
VALUES (<source_values>)

COMMIT

2
我会使用这个解决方案,而不是被采纳的答案,因为在我的应用中,我预计大部分情况下UPDATE操作都能成功。 - Sunian314
1
其实,为什么不使用合并语句呢?合并允许将源表合并到目标表中,并在必要时进行更新、插入和删除,一次性完成所有操作。 - Sunian314

1

这难道不是最优雅的吗?

REPLACE 
INTO component_psar (tbl_id, row_nr, col_1, col_2, col_3, col_4, col_5, col_6, unit, add_info, fsar_lock) 
VALUES('2', '1', '1', '1', '1', '1', '1', '1', '1', '1', 'N')

请参见: http://dev.mysql.com/doc/refman/5.7/en/replace.html


我可以在这里使用多个值吗?比如: INSERT INTO table VALUES (1, 2, 3), (4, 5, 6) 等等..? - Robert de Jonge
2
这取决于您是否想保留主键/自增字段。如果使用REPLACE,它会在插入之前删除原始行(如果存在)。此外,请注意,如果您有大量带有索引的记录,则删除可能需要很长时间,在这种情况下,如果记录已经存在,则这些操作是不必要的。 - PrestonDocks

0
请使用以下语句:
IF EXISTS(SELECT * FROM prueba )
then
  UPDATE prueba
  SET nombre = '1', apellido = '1' 
  WHERE cedula = 'ct'
ELSE 
  INSERT INTO prueba (cedula, nombre, apellido)
  VALUES ('ct', 'ct', 'ct');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接