it-swarm.com.ru

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

Я начал с поиска в Google и нашел это статья , в которой говорится о мьютексных таблицах.

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

Гарантирует ли ограничение unique для поля, что insert потерпит неудачу, если он уже существует?

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

748
warren

используйте 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 :

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-запросов.

733
knittl
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 
173
Server

при обновлении дублированного ключа или вставьте игнорировать могут быть жизнеспособными решениями с 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
Zed

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

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

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

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

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

24
KLE

Вот функция 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
Jrm
REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;

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

18
Rocio

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

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
Jeb's

Есть несколько ответов, которые описывают, как решить эту проблему, если у вас есть индекс 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, который зависит от NOT EXISTS, т.е. INSERT выполняется только тогда, когда набор данных не существует.

5
wortwart

Пытаться:

// 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
Andrea php