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逻辑,我可以避免这种非常可怕的黑客攻击吗?
答案 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指定为虚拟表名
答案 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