2010-07-02 2 views
235

Я пытаюсь выполнить следующий запрос:MySQL: Вставка записи, если не существует в таблице

INSERT INTO table_listnames (name, address, tele) 
VALUES ('Rupert', 'Somewhere', '022') 
WHERE NOT EXISTS (
    SELECT name FROM table_listnames WHERE name='value' 
); 

Но это возвращает ошибку. В принципе, я не хочу вставлять запись, если поле «имя» записи уже существует в другой записи - как проверить, уникально ли новое имя?

+3

Возможный дубликат [Как «вставить, если не существует» в MySQL?] (http://stackoverflow.com/questions/1361340/how-to-insert-if-not-exists -in-mysql) – warren

+5

Все текущие ответы на это или обманы предполагают, что вы можете добавить уникальный индекс. Иногда решение основано на бизнес-логике, которая не может быть наложена на всю таблицу. Например, вы разрешаете несколько строк с определенным значением в столбце, но другое значение в столбце разрешено показывать только в одной строке. Как это сделать? – Oscar

+0

см. Также: http://stackoverflow.com/q/1361340/4418 – warren

ответ

341

Я на самом деле не предполагая, что вы делаете это, как индекс UNIQUE как предложено Piskvor и другие это гораздо лучший способ сделать это, но вы можете делать то, что вы пытаетесь:

CREATE TABLE `table_listnames` (
    `id` int(11) NOT NULL auto_increment, 
    `name` varchar(255) NOT NULL, 
    `address` varchar(255) NOT NULL, 
    `tele` varchar(255) NOT NULL, 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB; 

Вставьте запись:

INSERT INTO table_listnames (name, address, tele) 
SELECT * FROM (SELECT 'Rupert', 'Somewhere', '022') AS tmp 
WHERE NOT EXISTS (
    SELECT name FROM table_listnames WHERE name = 'Rupert' 
) LIMIT 1; 

Query OK, 1 row affected (0.00 sec) 
Records: 1 Duplicates: 0 Warnings: 0 

SELECT * FROM `table_listnames`; 

+----+--------+-----------+------+ 
| id | name | address | tele | 
+----+--------+-----------+------+ 
| 1 | Rupert | Somewhere | 022 | 
+----+--------+-----------+------+ 

Попробуйте вставить ту же запись снова:

INSERT INTO table_listnames (name, address, tele) 
SELECT * FROM (SELECT 'Rupert', 'Somewhere', '022') AS tmp 
WHERE NOT EXISTS (
    SELECT name FROM table_listnames WHERE name = 'Rupert' 
) LIMIT 1; 

Query OK, 0 rows affected (0.00 sec) 
Records: 0 Duplicates: 0 Warnings: 0 

+----+--------+-----------+------+ 
| id | name | address | tele | 
+----+--------+-----------+------+ 
| 1 | Rupert | Somewhere | 022 | 
+----+--------+-----------+------+ 

Вставьте другую запись:

INSERT INTO table_listnames (name, address, tele) 
SELECT * FROM (SELECT 'John', 'Doe', '022') AS tmp 
WHERE NOT EXISTS (
    SELECT name FROM table_listnames WHERE name = 'John' 
) LIMIT 1; 

Query OK, 1 row affected (0.00 sec) 
Records: 1 Duplicates: 0 Warnings: 0 

SELECT * FROM `table_listnames`; 

+----+--------+-----------+------+ 
| id | name | address | tele | 
+----+--------+-----------+------+ 
| 1 | Rupert | Somewhere | 022 | 
| 2 | John | Doe  | 022 | 
+----+--------+-----------+------+ 

и так далее ...

+9

Спасибо, что помогли. Моя фактическая проблема намного сложнее, и столбец просто не может быть уникальным, и я не могу зависеть от первичного ключа. Но это именно то, что я искал. – Rupert

+0

Это сработает, но меня немного беспокоит производительность - если нет индекса на 'name', самый внутренний выбор будет ужасно медленным. Если есть индекс, то это должно работать нормально. – Piskvor

+2

@Piskovar: Согласен[email protected]: вы должны индексировать столбец, упомянутый во внутреннем операторе select ('name', в этом случае), если это вообще возможно. Также обратите внимание, что вы можете делать SELECT «John», «Doe», «022» FROM table_listnames' вместо «SELECT * FROM» (SELECT «John», «Doe», «022») AS tmp', но это будет работают только в том случае, если 'table_listnames' уже содержит одну или несколько строк. Я сомневаюсь, что скорость отличается от других, так что, вероятно, это не проблема. – Mike

2

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

+0

вещь я не могу установить ее первичной или уникальной – Rupert

216

INSERT doesn't allow WHERE in the syntax.

Что вы можете сделать: создать UNIQUE INDEX на поле, которое должно быть уникальным (name), то можно использовать:

  • нормальный INSERT (и обработать ошибку, если имя уже существует)
  • INSERT IGNORE (который будет с ошибкой вызывать предупреждение (вместо ошибки), если имя уже существует)
  • INSERT ... ON DUPLICATE KEY UPDATE (который будет исполнять UPDATE в конце, если имя уже существует, see documentation)
+8

Благодарим за предоставленные варианты. INSERT IGNORE помог мне. – Xynariz

+14

Спасибо, 5 лет спустя, и все еще помогаю людям :). – Andrew

+6

5 лет спустя и все еще помогая ppl :) – motan

11

Если вы действительно не можете получить уникальный индекс на столе, вы могли бы попробовать ...

INSERT INTO table_listnames (name, address, tele) 
    SELECT 'Rupert', 'Somewhere', '022' 
     FROM some_other_table 
     WHERE NOT EXISTS (SELECT name 
           FROM table_listnames 
           WHERE name='Rupert') 
     LIMIT 1; 
3

Brian Hooper: Вы почти попали в точку, но у вас есть ошибка в вашем синакс. Ваша вставка никогда не будет работать. Я проверил в своей базе данных и вот правильный ответ:

INSERT INTO podatki (datum,ura,meritev1,meritev1_sunki,impulzi1,meritev2,meritev2_sunki,impulzi2) 
      SELECT '$datum', '$ura', '$meritve1','$sunki1','$impulzi1','$meritve2','$sunki2','$impulzi2' 
       FROM dual 
       WHERE NOT EXISTS (SELECT datum,ura 
             FROM podatki 
             WHERE datum='$datum' and ura='$ura' 

Я даю вам свой пример таблицы y. Вставка почти такая же, как писал Биан Хупер, за исключением того, что я помещаю select FROM DUAL ont из другой таблицы. CIND С уважением, Иван

+2

Что это за «двойное»? Встроенное ключевое слово? Я просто не вижу разницы с тем, что сказал Брайан ... EDIT: Дальнейшие исследования были неоднозначными и противоречивыми (?) Результатами. Хотя на странице [SQL DUAL table] (http://www.w3resource.com/sql/sql-dual-table.php) говорится, что MySQL не поддерживает таблицы DUAL, [руководство по MySQL] (http: //dev.mysql .com/doc/refman/5.0/ru/select.html) говорит, что это так. Мой собственный тест показывает, что он этого не делает, поскольку он дает сообщение 'unknown table status: TABLE_TYPE', хотя запрос дал результат. Вероятно, потому что MySQL не требует предложения 'FROM DUAL'? – not2qubit

15
INSERT IGNORE INTO `mytable` 
SET `field0` = '2', 
`field1` = 12345, 
`field2` = 12678; 

Здесь MySQL запросов, что вставка записей, если не существует и будет игнорировать существующие аналогичные записи.

----Untested---- 
+4

это не сработало для меня, INSERT IGNORE INTO emAssignedTagsForEvent SET eventId = '2', defaultTagId = '1'; – pitu

+6

Похож на смесь синтаксисов вставки и обновления. Вы имеете в виду '' INSERT IGNORE INTO 'mytable' (' field0', 'field1',' field2') значения ('2', 12345, 12678); ''? – Hobo

+0

@Hobo From MySQL Manual https://dev.mysql.com/doc/refman/5.7/en/insert.html Синтаксис INSERT: Это может быть 'INSERT [...] IGNORE INTO mytable VALUES ...' Или 'INSERT [...] IGNORE INTO mytable SET col_name = {expr | DEFAULT}, ... ' – Shirkam

37

Работал:

INSERT INTO users (full_name, login, password) 
    SELECT 'Mahbub Tito','tito',SHA1('12345') FROM DUAL 
WHERE NOT EXISTS 
    (SELECT login FROM users WHERE login='tito'); 
+0

Это работает только для баз данных Oracle?https://en.wikipedia.org/wiki/DUAL_table Этот вопрос касается, в частности, MySQL! –

+0

Я не тестирую базу данных Oracle. Он отлично работает в MySQL и тестируется. –

+3

Я с тех пор узнал, что «dual» доступен в MySQL, но не в MariaDB, ветвь с открытым исходным кодом MySQL –

10

Для преодоления подобной проблемы, я сделал таблицу я вставив иметь уникальный столбец. Используя ваш пример, на создании я бы что-то вроде:

name VARCHAR(20), 
UNIQUE (name) 

, а затем использовать следующий запрос при вставке в него:

INSERT IGNORE INTO train 
set table_listnames='Rupert' 
3
insert into customer_keyskill(customerID, keySkillID) 
select 2,1 from dual 
where not exists ( 
    select customerID from customer_keyskill 
    where customerID = 2 
    and keySkillID = 1) 
+0

dual - это таблица Oracle, а не MySQL –

17

MySQL обеспечивает очень симпатичное решение:

REPLACE INTO `table` VALUES (5, 'John', 'Doe', SHA1('password')); 

Очень прост в использовании, так как вы объявили уникальный первичный ключ (здесь со значением 5).

+2

Но она обновляет запись (посмотрите на затронутые строки) – Azmeer

+0

, чтобы предотвратить ее создание уникальный индекс, больше информации здесь: [link] (http://stackoverflow.com/questions/5835978/how-to-properly-create-composite-primary-keys-mysql) – Azmeer

2

У меня была проблема, и метод Майк посоветовал работал частично, у меня было имя ошибки продублируйте Колонка = «0», и изменил синтаксис запроса, как this`

 $tQ = "INSERT INTO names (name_id, surname_id, sum, sum2, sum3,sum4,sum5) 
       SELECT '$name', '$surname', '$sum', '$sum2', '$sum3','$sum4','$sum5' 
FROM DUAL 
       WHERE NOT EXISTS (
       SELECT sum FROM names WHERE name_id = '$name' 
AND surname_id = '$surname') LIMIT 1;"; 

Проблема была с имена столбцов. sum3 был равен sum4 и MySQL забросил продублируйте имена столбцов, и я написал код в синтаксисе, и она работала отлично,

+0

Спасатель жизни, спасибо помощнику! – Areeb

5

Этот запрос работает хорошо:

INSERT INTO `user` (`username` , `password`) 
    SELECT * FROM (SELECT 'ersks', md5('Nepal')) AS tmp 
    WHERE NOT EXISTS (SELECT `username` FROM `user` WHERE `username` = 'ersks' 
    AND `password` = md5('Nepal')) LIMIT 1 

И вы можете создать таблицу, используя следующий запрос :

CREATE TABLE IF NOT EXISTS `user` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `username` varchar(30) NOT NULL, 
    `password` varchar(32) NOT NULL, 
    `status` tinyint(1) DEFAULT '0', 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 

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

0

У меня была аналогичная проблема, и мне нужно было вставить несколько, если они не были. Поэтому из приведенных выше примеров я пришел к этой комбинации ... это здесь на всякий случай, если кому-то это понадобится.

Извещение: Мне нужно было определить имя везде как MSSQL, котор нужно оно ... MySQL работает с * слишком.

INSERT INTO names (name) 
SELECT name 
FROM 
(
    SELECT name 
    FROM 
    (
    SELECT 'Test 4' as name 
) AS tmp_single 
    WHERE NOT EXISTS 
    (
    SELECT name FROM names WHERE name = 'Test 4' 
) 
    UNION ALL 
    SELECT name 
    FROM 
    (
    SELECT 'Test 5' as name 
) AS tmp_single 
    WHERE NOT EXISTS 
    (
    SELECT name FROM names WHERE name = 'Test 5' 
) 
) tmp_all; 

MySQL: CREATE TABLE names ( OID INT (11) NOT NULL AUTO_INCREMENT, name VARCHAR (32) COLLATE utf8_unicode_ci NOT NULL, первичный ключ (OID), уникальный ключ name_UNIQUE (name) ) ENGINE = InnoDB AUTO_INCREMENT = 1;

или

MSSQL: CREATE TABLE [имена] ( [OID] INT IDENTITY (1, 1) NOT NULL, [имя] NVARCHAR (32) NOT NULL, ПЕРВИЧНЫЙ КЛЮЧ CLUSTERED ([OID ] ASC) ); CREATE UNIQUE NONCLUSTERED INDEX [Index_Names_Name] ON [имена] ([имя] ASC);

5

Вы можете легко использовать следующим образом:

INSERT INTO ..... ON DUPLICATE KEY UPDATE ... 

Этим способом вы можете вставить любой новый сырье, и если у вас есть повторяющиеся данные, заменить конкретный столбец (лучший столбец метки времени).
Например:

CREATE TABLE IF NOT EXISTS Devices (
    id   INT(6)  NOT NULL AUTO_INCREMENT, 
    unique_id VARCHAR(100) NOT NULL PRIMARY KEY, 
    created_at VARCHAR(100) NOT NULL, 
    UNIQUE KEY unique_id (unique_id), 
    UNIQUE KEY id (id) 
) 
    CHARACTER SET utf8 
    COLLATE utf8_unicode_ci; 

INSERT INTO Devices(unique_id, time) 
VALUES('$device_id', '$current_time') 
ON DUPLICATE KEY UPDATE time = '$current_time'; 
0

Этот запрос может быть использован в PHP коде.

У меня есть столбец ID в этой таблице, так что мне нужно проверить для дублирования для всех столбцов, кроме этого ID колонки:

#need to change values 
SET @goodsType = 1, @sybType=5, @deviceId = asdf12345SDFasdf2345;  


INSERT INTO `devices` (`goodsTypeId`, `goodsId`, `deviceId`) #need to change tablename and columnsnames 
SELECT * FROM (SELECT @goodsType, @sybType, @deviceId) AS tmp 
WHERE NOT EXISTS (
    SELECT 'goodsTypeId' FROM `devices` #need to change tablename and columns names 
    WHERE `goodsTypeId` = @goodsType 
     AND `goodsId` = @sybType 
     AND `deviceId` = @deviceId 
) LIMIT 1; 

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

Смежные вопросы