Reputation: 627
I'm working with a job queue that will have many schedulers and workers tapping into it, with some schedulers even trying to queue the same job. I want to make sure the same job isn't added if it's already there with a "pending" status.
The table has a unique ID field for code-generated UUIDs. A distinct job is identified by its name and parameters.
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'
);
This is resulting in a duplicate key error on the ID, even though that ID definitely does NOT exist in the table beforehand.
Why is this happening? Is there a way to compensate?
Edit: Since nobody seems to believe me..,
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)
Upvotes: 0
Views: 48
Reputation: 31792
If the subquery returns no row, the NOT EXISTS (...)
expression will return TRUE
(or 1
). In that case the query will try to insert as much rows (with the same constant values) as do exist in the job
table, thus raising a duplicate key error for the id
column. All you need to change is to select from any one-row-table. In MySQL you can use FROM dual
or a subquery (select 1)
. So your query could be:
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'
);
You can also just wrap your values in a subquery (one-row derived table):
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'
);
Upvotes: 1