INSERT w / SELECT子查询和重复键错误

时间:2018-03-14 22:33:43

标签: mysql

我正在使用一个作业队列,该作业队列将有许多调度程序和工作人员使用它,一些调度程序甚至尝试排队同一个作业。我想确保同样的工作没有添加,如果它已经存在"待定"状态。

该表具有代码生成的UUID的唯一ID字段。 通过名称和参数来识别不同的工作。

INSERT INTO job (id,name,parameters)
SELECT '3aa39ed8-bac8-454a-88e1-626ce6e69228', 'process_summaries', '{}'
FROM job
WHERE NOT EXISTS (
    SELECT 1 FROM job
    WHERE name = 'process_summaries'
    AND parameters = '{}'
    AND status = 'pending'
);

这会导致ID上出现重复的键错误,即使该表中的ID确实不存在。

为什么会这样?有没有办法补偿?

编辑: 因为似乎没有人相信我..,

mysql> SELECT * FROM job WHERE id='3aa39ed8-bac8-454a-88e1-626ce6e69228';
Empty set (0.00 sec)

mysql> INSERT INTO job (id,name,parameters)
    -> SELECT '3aa39ed8-bac8-454a-88e1-626ce6e69228', 'process_summaries', '{}'
    -> FROM job
    -> WHERE NOT EXISTS (
    ->     SELECT 1 FROM job
    ->     WHERE name = 'process_summaries'
    ->     AND parameters = '{}'
    ->     AND status = 'pending'
    -> );
ERROR 1062 (23000): Duplicate entry '3aa39ed8-bac8-454a-88e1-626ce6e69228' for key 'PRIMARY'

mysql> SELECT * FROM job WHERE id='3aa39ed8-bac8-454a-88e1-626ce6e69228';
Empty set (0.00 sec)

1 个答案:

答案 0 :(得分:1)

如果子查询没有返回任何行,NOT EXISTS (...)表达式将返回TRUE(或1)。在这种情况下,查询将尝试插入job表中存在的尽可能多的行(具有相同的常量值),从而引发id列的重复键错误。您需要更改的是从任何一行表中进行选择。在MySQL中,您可以使用FROM dual或子查询(select 1)。所以你的查询可能是:

INSERT INTO job (id,name,parameters)
SELECT '3aa39ed8-bac8-454a-88e1-626ce6e69228', 'process_summaries', '{}'
FROM dual
WHERE NOT EXISTS (
    SELECT 1 FROM job
    WHERE name = 'process_summaries'
    AND parameters = '{}'
    AND status = 'pending'
);

您也可以将值包装在子查询中(单行派生表):

INSERT INTO job (id,name,parameters)
SELECT *
FROM (SELECT '3aa39ed8-bac8-454a-88e1-626ce6e69228', 'process_summaries', '{}') sub
WHERE NOT EXISTS (
    SELECT 1 FROM job
    WHERE name = 'process_summaries'
    AND parameters = '{}'
    AND status = 'pending'
);