0

INSERT IGNORE doesn't work because there won't actually be a key conflict.

This is for a progress queue. For one application I don't want two rows with status S (for "started"). However other applications should be able to - in particular if I want to force two work items to happen at once, I can. So that's why it's not a database constraint.

So it's a little tricky to say in SQL "insert where does not exist." This works:

insert into user_queue_google
(user_id, status, start_timestamp)
(select 221, 'S', NOW() FROM filter_type
WHERE 221 not in (select user_id from user_queue_google where status = 'S') limit 1);

The problem is filter_type is a completely unrelated table that I just know is small and happens to never be empty. If it were empty for some reason, this would fail.

Can I avoid this very horrible hack without resorting to stored programs or IF/THEN logic in my SQL program?

pilcrow
  • 56,591
  • 13
  • 94
  • 135
djechlin
  • 59,258
  • 35
  • 162
  • 290
  • possible duplicate of [MySQL Conditional Insert](http://stackoverflow.com/questions/913841/mysql-conditional-insert) – pilcrow Oct 03 '13 at 15:47

3 Answers3

0

use the dual system dummy table

insert into user_queue_google (user_id, status, start_timestamp)
select 221, 'S', NOW()
from dual
WHERE not exists 
(
   select user_id 
   from user_queue_google 
   where status = 'S' 
   and user_id = 221
)

You are permitted to specify DUAL as a dummy table name in situations where no tables are referenced

Source

juergen d
  • 201,996
  • 37
  • 293
  • 362
0

You need to have a UNIQUE index for INSERT IGNORE to work effectively. What you could do is add an additional column that defaults to something harmless but could be changed to unique the key:

CREATE UNIQUE INDEX index_block ON user_queue_google (user_id, force);

Set force as a column that has DEFAULT 0. If you want to force two jobs to run at the same time, set it to something else to avoid a conflict:

UPDATE user_queue_google SET status='S', force=UNIX_TIMESTAMP() WHERE user_id=221

That'll free up a new slot for inserting new jobs.

tadman
  • 208,517
  • 23
  • 234
  • 262
0

This should work:

insert into user_queue_google
(user_id, status, start_timestamp)
select
    A.user_id,
    A.status,
    A.start_timestamp
FROM
  (SELECT
     221 user_id, 
     'S' status, 
     NOW() start_timestamp) AS A
  LEFT JOIN user_queue_google ON A.user_id = user_queue_google.user_id AND A.status = user_queue_google.status
WHERE
   user_queue_google.user_id IS NULL;

See attached fiddle Insert if row doesn't exist

Tobsey
  • 3,390
  • 14
  • 24