Как вставить, если не существует в MySQL?
Я начал с Google, и нашел это статьи что говорит о таблицах мьютексов.
у меня есть таблица с ~14 миллионов записей. Если я хочу добавить больше данных в том же формате, есть ли способ убедиться, что запись, которую я хочу вставить, уже не существует без использования пары запросов (т. е. один запрос для проверки и один для вставки-это пустой результирующий набор)?
тут unique ограничение на поле гарантию insert не получится, если это уже там?
похоже, что с просто ограничение, когда я выдаю вставку через php, скрипт хрипит.
9 ответов:
использовать
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 согласно webcache от Google:
18 октября 2007
для начала: начиная с последней версии 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) повторные исполнения трубопровода не разрушат наше база данных, и 2) повторные исполнения не умрет из-за " дубликат ошибки первичного ключа.
метод 1: Использование REPLACE
Это очень просто:
REPLACE INTO `transcripts` SET `ensembl_transcript_id` = ‘ENSORGT00000000001′, `transcript_chrom_start` = 12345, `transcript_chrom_end` = 12678;если запись существует, она будет перезаписана; если она еще не существует существует, он будет создан. Однако использование этого метода не является эффективным для нашего случая: нам не нужно перезаписывать существующие записи, это нормально просто, чтобы пропустить их.
Метод 2: с помощью вставки игнорировать также очень просто:
INSERT IGNORE INTO `transcripts` SET `ensembl_transcript_id` = ‘ENSORGT00000000001′, `transcript_chrom_start` = 12345, `transcript_chrom_end` = 12678;здесь, если 'ensembl_transcript_id' уже присутствует в база данных, она будет молча пропущена (проигнорирована). (Если быть более точным, вот цитата из справочного руководства MySQL: "если вы используете IGNORE ключевое слово, ошибки, которые возникают при выполнении инструкции INSERT являются вместо этого рассматривается как предупреждение. Например, без игнорирования, строка, которая дублирует существующий уникальный индекс или значение первичного ключа в таблице вызывает ошибку повторяющегося ключа и оператор прерывается.".) Если запись еще не существует, она будет создана.
этот второй метод имеет несколько потенциальных недостатков, в том числе не прерывание запроса в случае возникновения каких-либо других проблем (см. руководство.) Таким образом он должен быть использован если ранее испытанный без Игнорировать ключевое слово.
есть еще один вариант: использовать INSERT ... на дубликат ключа ОБНОВЛЕНИЕ синтаксис, а в части обновления просто ничего не делать какие-то бессмысленные (пустая) операция, например вычисление 0+0 (Geoffray предлагает выполнить id=назначение id для механизма оптимизации MySQL, чтобы игнорировать это операция.) Преимущество этого метода заключается в том, что он игнорирует только дубликат ключевые события, и все еще прерывает на других ошибках.
в качестве последнего уведомления: этот пост был вдохновлен 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 [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] ... ]
любое простое ограничение должно выполнять эту работу, если исключение приемлемо. Примеры:
- первичный ключ, если не суррогат
- уникальное ограничение на столбец
- ограничение уникальности нескольких столбцов
извините, это кажется обманчиво простым. Я знаю, что это выглядит плохо, столкнувшись с ссылкой, которую вы делите с нами. ;-(
но я никогда не даю этот ответ, потому что он, кажется, заполняет вашу потребность. (Если нет, это может вызвать обновление ваши требования, которые были бы "хорошей вещью"(TM) также).
редактировать: если вставка нарушит ограничение уникальности базы данных, на уровне базы данных создается исключение, ретранслируемое драйвером. Это, безусловно, остановит ваш сценарий, с неудачей. В PHP должно быть возможно обратиться к этому случаю ...
REPLACE INTO `transcripts` SET `ensembl_transcript_id` = 'ENSORGT00000000001', `transcript_chrom_start` = 12345, `transcript_chrom_end` = 12678;если запись существует, она будет перезаписана; если она еще не существует, она будет создана.
вот функция 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' ) ); ?>
попробуйте следующее:
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
попробуй:
// 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 } }этот метод является быстрым и легким. Для повышения скорости выполнения запроса в вашей большой таблице индексных столбцов ' xxx ' (в моем примере ).
есть несколько ответов, которые охватывают как решить эту проблему, если у вас есть
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выполняется только тогда, когда набор данных не существует.
Comments