Php 如何在MySQL中“如果不存在则插入”?

Php 如何在MySQL中“如果不存在则插入”?,php,mysql,sql,primary-key,sql-insert,Php,Mysql,Sql,Primary Key,Sql Insert,我从谷歌搜索开始,发现这是关于互斥表的 我有一张有1400万张唱片的桌子。如果我想以相同的格式添加更多数据,是否有办法确保我要插入的记录不存在,而不使用一对查询,即,一个要检查的查询和一个要插入的查询的结果集是否为空 字段上的唯一约束是否保证插入操作在已存在的情况下会失败 似乎只有一个约束,当我通过php发出insert命令时,脚本就会发出嘎嘎声。如果可以接受异常,任何简单的约束都可以完成任务。示例: 主键(如果不是代理项) 列上的唯一约束 多列唯一约束 对不起,这看起来很简单。我知道你和我们分

我从谷歌搜索开始,发现这是关于互斥表的

我有一张有1400万张唱片的桌子。如果我想以相同的格式添加更多数据,是否有办法确保我要插入的记录不存在,而不使用一对查询,即,一个要检查的查询和一个要插入的查询的结果集是否为空

字段上的唯一约束是否保证插入操作在已存在的情况下会失败


似乎只有一个约束,当我通过php发出insert命令时,脚本就会发出嘎嘎声。

如果可以接受异常,任何简单的约束都可以完成任务。示例:

主键(如果不是代理项) 列上的唯一约束 多列唯一约束 对不起,这看起来很简单。我知道你和我们分享的链接看起来很糟糕-

但我从未给出过这个答案,因为它似乎满足了你的需要。如果没有,它可能会触发您更新您的需求,这也是一件好事TM

编辑:如果插入将打破数据库唯一性约束,则会在数据库级别引发异常,并由驱动程序转发。它肯定会停止您的脚本,但会失败。在PHP中必须能够处理这种情况…

使用INSERT IGNORE到表中

还有INSERT…关于重复密钥更新语法,您可以在

从bogdan.org.ua发布,根据:

2007年10月18日

首先:从最新的MySQL开始,标题中显示的语法不是 可能的但有几种非常简单的方法可以实现真正的目标 预期使用现有功能

有3种可能的解决方案:使用插入忽略、替换或 在重复密钥更新时插入

假设我们有一张桌子:

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:使用替换

很简单:

REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
如果该记录存在,将被覆盖;如果还没有 如果存在,它将被创建。然而,使用这种方法并不有效 对于我们的情况:我们不需要覆盖现有记录,这很好 只是为了跳过它们

方法2:使用INSERT IGNORE也非常简单:

REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
这里,如果“ensembl_转录本_id”已经存在于 数据库,它将被自动跳过或忽略。更确切地说,, 这里引用了MySQL参考手册中的一句话:“如果您使用忽略 关键字,执行INSERT语句时发生的错误包括 改为视为警告。例如,在不忽略的情况下,一行 复制表中现有的唯一索引或主键值 导致重复键错误,并且语句被中止。“。如果 记录尚不存在,将创建该记录

第二种方法有几个潜在的弱点,包括 如果出现任何其他问题,则不终止查询请参阅 手册因此,如果之前测试时未使用 忽略关键字

方法3:在重复密钥更新时使用INSERT…:

第三个选项是在重复密钥更新时使用INSERT 语法,在更新部分什么都不做,做一些没有意义的事情 空操作,如计算0+0 Geoffray建议执行 id=MySQL优化引擎忽略此项的id分配 活动这种方法的优点是它只忽略重复项 键事件,但仍会中止其他错误

最后一点:这篇文章的灵感来自Xaprb。我还建议 参考他的另一篇关于编写灵活的SQL查询的文章

,也可以是MySQL的可行解决方案

基于mysql.com的更新示例

基于mysql.com的示例

或:

或:

解决方案:

说明:

最里面的查询

SELECT * FROM `table` 
      WHERE `value1`='stuff for value1' AND `value2`='stuff for value2' LIMIT 1
用作WHERE NOT EXISTS条件,用于检测是否已经存在包含要插入的数据的行。找到此类行后,查询可能会停止,因此可能会忽略限制1微优化

中间查询

SELECT 'stuff for value1', 'stuff for value2' FROM DUAL
表示要插入的值。DUAL是指默认情况下在所有Oracle数据库中都存在的一个特殊的一行一列表,请参阅。在MySQL服务器版本5.7.26上,当从DUAL中省略时,我得到了一个有效的查询,但是像5.5.60这样的旧版本似乎需要FROM信息。通过使用WHERE NOT EXISTS,如果最内层的查询找到匹配的数据,中间查询将返回一个空结果集

外部查询

INSERT INTO `table` (`value1`, `value2`) 
插入中间查询返回的数据(如果有)。

<
应该使用。选择MySQL API时,请参阅以获取更多帮助。您能否提供有关如何使用此API的更多信息?如果表中不存在唯一键,则此变体适用于插入忽略和插入重复键需要唯一键约束如果您在第2行使用“从双”而不是“从表”使用,那么您就不需要limit 1子句了。如果value1的内容和value2的内容相同呢?这将抛出一个重复的列名。我也更喜欢在子查询中选择1而不是选择*。更可能的是,这可以通过索引得到满足。有关不燃烧auto_inc值的讨论,请参阅。@RickJames-这是一个有趣的问题。。但不确定这是否与这个问题有直接关系:有人在评论中提到了这个问题,而另一个问题则声称这个问题完全是重复的。因此,我觉得为了其他人的利益,将问题链接在一起是一个好主意。哦,我从来没有想过看侧栏。替换可能会删除行,然后插入而不是更新。副作用是约束可能会删除其他对象并触发删除触发器。从MySQL手册中可以看出:只有在表具有主键或唯一索引时,替换才有意义。否则,它就等同于INSERT,因为没有用于确定新行是否与另一行重复的索引。试试看,这些答案在StackOverflow上的价值很低,因为它们对OP和数千名未来研究人员的教育作用甚微。请编辑此答案,以包括解决方案的工作原理以及为什么这是一个好主意。如果要匹配的字段不是键,则是完美的解决方案。。!为什么主键中的缺口——甚至可能——会使程序员精神不稳定?在主键中总是会出现空白-例如,每次你删除一条记录时。从SELECT开始就无法实现只发送一大批插入内容而不想担心重复内容的全部目的。其他几个回答者已经向。。。从格式中选择。“你为什么也这么做?”沃伦:要么你没有读我的答案,要么你不理解,要么我没有正确解释。无论如何,让我强调以下几点:这不仅仅是一个常规插入。。。从…中选择。。。解决方案请给我一个与答案相同的链接,如果你能找到,我将删除此答案,否则你将放弃我的答案交易?。确保您要链接的答案只使用1个查询进行更新+插入,没有事务,并且能够针对已知唯一的列的任何组合,因此这些列不需要单独唯一。
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]
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) 
SELECT * FROM `table` 
      WHERE `value1`='stuff for value1' AND `value2`='stuff for value2' LIMIT 1
SELECT 'stuff for value1', 'stuff for value2' FROM DUAL
INSERT INTO `table` (`value1`, `value2`) 
function insert_unique($table, $vars)
{
  if (count($vars)) {
    $table = mysql_real_escape_string($table);
    $vars = array_map('mysql_real_escape_string', $vars);

    $req = "INSERT INTO `$table` (`". join('`, `', array_keys($vars)) ."`) ";
    $req .= "SELECT '". join("', '", $vars) ."' FROM DUAL ";
    $req .= "WHERE NOT EXISTS (SELECT 1 FROM `$table` WHERE ";

    foreach ($vars AS $col => $val)
      $req .= "`$col`='$val' AND ";

    $req = substr($req, 0, -5) . ") LIMIT 1";

    $res = mysql_query($req) OR die();
    return mysql_insert_id();
  }

  return False;
}
<?php
insert_unique('mytable', array(
  'mycolumn1' => 'myvalue1',
  'mycolumn2' => 'myvalue2',
  'mycolumn3' => 'myvalue3'
  )
);
?>
REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
IF (SELECT COUNT(*) FROM beta WHERE name = 'John' > 0)
  UPDATE alfa SET c1=(SELECT id FROM beta WHERE name = 'John')
ELSE
BEGIN
  INSERT INTO beta (name) VALUES ('John')
  INSERT INTO alfa (c1) VALUES (LAST_INSERT_ID())
END
UPDATE wp_postmeta SET meta_value = ? WHERE meta_key = ? AND post_id = ?;
INSERT INTO wp_postmeta (post_id, meta_key, meta_value) SELECT DISTINCT ?, ?, ? FROM wp_postmeta WHERE NOT EXISTS(SELECT * FROM wp_postmeta WHERE meta_key = ? AND post_id = ?);