我开始使用谷歌搜索,发现这篇文章讨论了互斥表。
我有一张约有 1400 万条记录的表格。如果我想以相同的格式添加更多数据,有没有办法确保我想要插入的记录不存在而不使用一对查询(即,一个查询要检查,一个要插入是结果集是空)?
对字段的unique
约束是否保证insert
如果已经存在则会失败?
似乎只有一个约束,当我通过 php 发出插入时,脚本呱呱叫。
使用INSERT IGNORE INTO table
见http://bogdan.org.ua/2007/10/18/mysql-insert-if-not-exists-syntax.html
还有INSERT … ON DUPLICATE KEY UPDATE
语法,你可以在dev.mysql.com找到解释
根据谷歌的网络摄像头发布来自 bogdan.org.ua:
2007 年 10 月 18 日
首先:从最新的 MySQL 开始,标题中提供的语法是不可能的。但是有几种非常简单的方法可以实现使用现有功能所期望的功能。
有 3 种可能的解决方案:使用 INSERT IGNORE,REPLACE 或 INSERT ... ON DUPLICATE KEY UPDATE。
想象一下,我们有一张桌子:
CREATE TABLE `transcripts` ( `ensembl_transcript_id` varchar(20) NOT NULL, `transcript_chrom_start` int(10) unsigned NOT NULL, `transcript_chrom_end` int(10) unsigned NOT NULL, PRIMARY KEY (`ensembl_transcript_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
现在假设我们有一个自动管道从 Ensembl 导入转录元数据,并且由于各种原因导致管道在任何执行步骤都可能被破坏。因此,我们需要确保两件事:1)重复执行管道不会破坏我们的数据库,2)重复执行不会因 “重复主键” 错误而死亡。
方法 1:使用 REPLACE
这很简单:
REPLACE INTO `transcripts` SET `ensembl_transcript_id` = ‘ENSORGT00000000001′, `transcript_chrom_start` = 12345, `transcript_chrom_end` = 12678;
如果记录存在,它将被覆盖; 如果它还不存在,它将被创建。但是,对于我们的情况,使用此方法效率不高:我们不需要覆盖现有记录,只需跳过它们就可以了。
方法 2:使用 INSERT IGNORE 也非常简单:
INSERT IGNORE INTO `transcripts` SET `ensembl_transcript_id` = ‘ENSORGT00000000001′, `transcript_chrom_start` = 12345, `transcript_chrom_end` = 12678;
这里,如果'ensembl_transcript_id' 已经存在于数据库中,它将被静默跳过(忽略)。 (更准确地说,这是 MySQL 参考手册的引用:“如果使用 IGNORE 关键字,则执行 INSERT 语句时发生的错误将被视为警告。例如,没有 IGNORE,会复制现有 UNIQUE 索引的行表中的 PRIMARY KEY 值会导致重复键错误,并且语句将被中止。“。)如果该记录尚不存在,则会创建该记录。
第二种方法有几个潜在的弱点,包括在发生任何其他问题时不中止查询(参见手册)。因此,如果先前没有 IGNORE 关键字进行测试,则应该使用它。
还有一个选项:使用 INSERT ... ON DUPLICATE KEY UPDATE 语法,并且在 UPDATE 部分只是不做任何无意义(空)操作,比如计算 0 + 0(Geoffray 建议为 MySQL 优化做 id = id 赋值引擎忽略此操作)。此方法的优点是它只忽略重复的键事件,并仍然中止其他错误。
最后通知:这篇文章的灵感来自 Xaprb。我还建议查阅他关于编写灵活 SQL 查询的其他帖子。
INSERT INTO `table` (value1, value2)
SELECT 'stuff for value1', 'stuff for value2' FROM `table`
WHERE NOT EXISTS (SELECT * FROM `table`
WHERE value1='stuff for value1' AND value2='stuff for value2')
LIMIT 1
或者,外部SELECT
语句可以引用DUAL
以处理表最初为空的情况:
INSERT INTO `table` (value1, value2)
SELECT 'stuff for value1', 'stuff for value2' FROM DUAL
WHERE NOT EXISTS (SELECT * FROM `table`
WHERE value1='stuff for value1' AND value2='stuff for value2')
LIMIT 1
重复密钥更新 ,或插入忽略可以成为 MySQL 的可行解决方案。
基于 mysql.com 的重复密钥更新更新示例
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
UPDATE table SET c=c+1 WHERE a=1;
基于 mysql.com 的insert ignore示例
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
{VALUES | VALUE} ({expr | DEFAULT},...),(...),...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
要么:
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
SET col_name={expr | DEFAULT}, ...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
要么:
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]