如果相关行不存在则INSERT

时间:2013-10-03 15:31:25

标签: mysql sql insert

INSERT IGNORE不起作用,因为实际上不存在关键冲突。

这是一个进度队列。对于一个应用程序,我不希望两行状态为S(对于“已启动”)。然而,其他应用程序应该能够 - 特别是如果我想强制两个工作项同时发生,我可以。这就是为什么它不是数据库约束。

所以在SQL中说“插入不存在的地方”有点棘手。这有效:

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

问题是filter_type是一个完全不相关的表,我只知道它很小并且恰好永远不会是空的。如果由于某种原因它是空的,这将失败。

如果不在我的SQL程序中使用存储程序或IF / THEN逻辑,我可以避免这种非常可怕的黑客攻击吗?

3 个答案:

答案 0 :(得分:0)

使用dual系统虚拟表

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
)
  

在没有引用表的情况下,允许将DUAL指定为虚拟表名

Source

答案 1 :(得分:0)

您需要UNIQUE INSERT IGNORE索引才能有效运作。您可以做的是添加一个默认为无害的附加列,但可以将其更改为唯一键:

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

force设置为具有DEFAULT 0的列。如果要强制同时运行两个作业,请将其设置为其他内容以避免冲突:

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

这将释放一个用于插入新工作的新插槽。

答案 2 :(得分:0)

这应该有效:

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;

请参阅随附的小提琴Insert if row doesn't exist