仅当记录不存在时才将 SQL 插入表中[重复]
Posted
技术标签:
【中文标题】仅当记录不存在时才将 SQL 插入表中[重复]【英文标题】:SQL Insert into table only if record doesn't exist [duplicate] 【发布时间】:2013-05-03 20:20:33 【问题描述】:我想运行一组查询以将一些数据插入到 SQL 表中,但前提是满足某些条件的记录。该表有 4 个字段:id
(主)、fund_id
、date
和 price
我在查询中有 3 个字段:fund_id
、date
和 price
。
所以我的查询会是这样的:
INSERT INTO funds (fund_id, date, price)
VALUES (23, '2013-02-12', 22.43)
WHERE NOT EXISTS (
SELECT *
FROM funds
WHERE fund_id = 23
AND date = '2013-02-12'
);
所以我只想在不存在匹配fund_id
和date
的记录时插入数据。如果以上是正确的,我觉得这是一种非常低效的实现方式,因为每次都必须运行额外的 select 语句。
有没有更好的方法来实现上述目标?
编辑:为了澄清,fund_id
和 date
都不是唯一字段;将存在共享相同fund_id 或日期的记录,但没有记录应该具有与另一个相同的fund_id 和日期。
【问题讨论】:
您使用的是哪个 RDBMS? SQL Server、MySQ、Oracle、MSAccess? mysql 虽然我希望它也可以与 MSAccess 一起工作,如果 poss 查看***.com/questions/913841/mysql-conditional-insert 似乎 ID 和日期是您逻辑上唯一的键。为什么不声明它们是唯一的并在违反唯一键约束时处理数据库异常? 方法很好。但是,正如 Trinimon 的回答中指出的那样,您的 sql 无效。如果使用 values 关键字,则不能有 where 子句。 【参考方案1】:这可能是实现此目的的简单解决方案:
INSERT INTO funds (ID, date, price)
SELECT 23, DATE('2013-02-12'), 22.5
FROM dual
WHERE NOT EXISTS (SELECT 1
FROM funds
WHERE ID = 23
AND date = DATE('2013-02-12'));
p.s. 或者(如果 ID
是主键):
INSERT INTO funds (ID, date, price)
VALUES (23, DATE('2013-02-12'), 22.5)
ON DUPLICATE KEY UPDATE ID = 23; -- or whatever you need
见this Fiddle。
【讨论】:
这与我原来的方法有何不同/更好? 这没有什么不同。但它是有效的 SQL。 @harryg 你试过你的说法了吗? 好的,这个现在应该可以工作了(FROM dual
不见了)。调整了我的示例以适合您上面的代码
@ypercube 不,我还没有尝试过我的说法,因为此时它仍然是概念性的。那么dual
的目的是什么?我已经用谷歌搜索了,但不清楚这个语句是如何工作的......
这正是您想要做的。但是 MySQL 语法不允许在 INSERT ... VALUES
语句上使用 WHERE
。你必须用INSERT ... SELECT
重写。 dual
是一个只有一行的特殊表(它的用途是这样的,创建一个只有一行的表,以便可以插入到funds
中。)【参考方案2】:
虽然我最初标记为已选择的答案是正确的并且达到了我的要求,但有更好的方法来做到这一点(其他人承认但没有进入)。应在由fund_id
和date
组成的表上创建复合唯一索引。
ALTER TABLE funds ADD UNIQUE KEY `fund_date` (`fund_id`, `date`);
然后在插入记录时添加遇到冲突的条件:
INSERT INTO funds (`fund_id`, `date`, `price`)
VALUES (23, DATE('2013-02-12'), 22.5)
ON DUPLICATE KEY UPDATE `price` = `price`; --this keeps the price what it was (no change to the table) or:
INSERT INTO funds (`fund_id`, `date`, `price`)
VALUES (23, DATE('2013-02-12'), 22.5)
ON DUPLICATE KEY UPDATE `price` = 22.5; --this updates the price to the new value
这将为子查询提供更好的性能,并且表的结构更优越。它附带一个警告,您的唯一键列中不能有 NULL 值,因为它们仍然被 MySQL 视为值。
【讨论】:
您的解决方案运行良好,更整洁,看起来更优雅。但是,有性能差异吗?ON DUPLICATE KEY
不执行子查询吗?
UNIQUE 的性能取决于存储引擎。在 TokuDB 中,不鼓励这样做...
这不起作用【参考方案3】:
假设您无法修改 DDL(以创建唯一约束)或仅限于编写 DML,然后针对整个表检查您的值的过滤结果是否为空
FIDDLE
insert into funds (ID, date, price)
select
T.*
from
(select 23 ID, '2013-02-12' date, 22.43 price) T
left join
funds on funds.ID = T.ID and funds.date = T.date
where
funds.ID is null
【讨论】:
以上是关于仅当记录不存在时才将 SQL 插入表中[重复]的主要内容,如果未能解决你的问题,请参考以下文章