Как "вставить, если не существует" в MySQL?

Я начал с googling и нашел эту статью , которая рассказывает о таблицах мьютекса.

У меня есть таблица с ~ 14 миллионами записей. Если я хочу добавить больше данных в том же формате, есть ли способ гарантировать, что запись, которую я хочу вставить, уже не существует без использования пары запросов (т.е. Один запрос для проверки и один для вставки - это набор результатов пусто)?

Ограничение unique в поле гарантирует, что insert завершится с ошибкой, если он уже существует?

Похоже, что с просто ограничением, когда я выдаю вставку через php, script кричит.

+745
01 сент. '09 в 8:56
источник поделиться
11 ответов

использовать 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 по данным Google webcache :

18 октября 2007 г.

Для начала: с последней версии 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 предлагает выполнить присвоение id = id для оптимизации MySQL двигатель игнорировать эту операцию). Преимущество этого метода заключается в том, что он игнорирует только повторяющиеся ключевые события и по-прежнему прерывается при других ошибках.

В качестве последнего уведомления: этот пост был вдохновлен Xaprb. Я бы также посоветовал обратиться к его другому посту по написанию гибких SQL-запросов.

+730
01 сент. '09 в 9:02
источник

Связанные вопросы


Похожие вопросы

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 
+171
11 июн. '10 в 18:38
источник

при дублировании ключевого обновления или insert ignore может быть жизнеспособными решениями с 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 [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] ... ]
+52
01 сент. '09 в 9:05
источник

Любое простое ограничение должно выполнять задание, если исключение приемлемо. Примеры:

  • первичный ключ, если не суррогатный
  • уникальное ограничение для столбца
  • уникальное ограничение нескольких столбцов

Извините, это кажется обманчиво простым. Я знаю, что это плохо противостоит той ссылке, которую вы разделяете с нами.; - (

Но я никогда не даю этого ответа, потому что он, похоже, наполнит ваши потребности. (Если нет, это может спровоцировать ваше обновление ваших требований, что также будет "хорошей вещью" (TM).

Отредактировано. Если вставка нарушит уникальное ограничение базы данных, исключение - это выброс на уровне базы данных, передаваемый драйвером. Это, безусловно, остановит ваш script с ошибкой. В PHP должно быть возможно указать этот случай...

+24
01 сент. '09 в 9:01
источник

Вот PHP-функция, которая будет вставлять строку только в том случае, если все указанные значения столбцов еще не существуют в таблице.

  • Если один из столбцов отличается, строка будет добавлена.

  • Если таблица пуста, строка будет добавлена.

  • Если строка существует, где все указанные столбцы имеют указанные значения, строка не будет добавлена.

    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'
  )
);
?>
+18
06 мар. '12 в 19:56
источник
REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;

Если запись существует, она будет перезаписана; если он еще не существует, он будет создан.

+18
06 июл. '12 в 14:35
источник

Попробуйте следующее:

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
+17
10 мая '13 в 9:58
источник

Replace может работать для вас.

+10
01 сент. '09 в 9:02
источник

Существует несколько ответов, которые описывают, как это решить, если у вас есть индекс UNIQUE, с которым вы можете проверить с помощью ON DUPLICATE KEY или INSERT IGNORE. Это не всегда так, и поскольку UNIQUE имеет ограничение длины (1000 байт), вы не сможете его изменить. Например, мне пришлось работать с метаданными в WordPress (wp_postmeta).

Я, наконец, решил его с двумя запросами:

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

Запрос 1 является регулярным запросом UPDATE без эффекта, когда соответствующего набора данных нет. Запрос 2 - это INSERT, который зависит от a NOT EXISTS, т.е. INSERT выполняется только тогда, когда набор данных не существует.

+5
18 авг. '16 в 18:38
источник

Try:

// Check if exist cod = 56789
include "database.php";

$querycheck = mysql_query ("SELECT * FROM `YOURTABLE` WHERE `xxx` = '56789';");
$countrows = mysql_num_rows($querycheck);
if($countrows == '1')
{
  // Exist 
}
else
{
 // .... Not exist
}

Или вы можете сделать:

// Check if exist cod = 56789
include "database.php";

$querycheck = mysql_query ("SELECT * FROM `YOURTABLE` WHERE `xxx` = '56789';");
$countrows = mysql_num_rows($querycheck);
while($result = mysql_fetch_array($querycheck))
{
    $xxx = $result['xxx'];
    if($xxx == '56789')
    {
      // Exist
    }
    else
    {
      // Not exist
    }
}

Этот метод является быстрым и легким. Для улучшения скорости запроса в вашей большой таблице столбцы INDEX "xxx" (в моем примере).

+4
25 сент. '15 в 16:17
источник

вы можете либо запустить быстрый выбор, чтобы найти, существует ли он, а затем ничего не вставлять, они будут двумя инструкциями

или просто перейдите к

INSERT IGNORE INTO таблица

0
17 янв. '17 в 5:41
источник

Посмотрите другие вопросы по меткам или Задайте вопрос