2010-07-02 14 views
235

Ich versuche, die folgende Abfrage auszuführen:MySQL: Rekord Einfügen, wenn nicht in der Tabelle vorhanden ist

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

Aber dies einen Fehler zurück. Grundsätzlich möchte ich keinen Datensatz einfügen, wenn das 'Name'-Feld des Datensatzes bereits in einem anderen Datensatz existiert - wie überprüft man, ob der neue Name eindeutig ist?

+3

mögliche Duplikat von [Wie einfügen ', wenn nicht existiert' in MySQL?] (http://StackOverflow.com/Questions/1361340/How-to-insert-if-not-exists -in-mysql) – warren

+5

Alle aktuellen Antworten auf diese oder die Duples gehen davon aus, dass Sie einen eindeutigen Index hinzufügen können. Manchmal basiert die Entscheidung auf einer Geschäftslogik, die nicht dem gesamten Tisch auferlegt werden kann. Wenn Sie beispielsweise mehrere Zeilen mit einem bestimmten Wert in einer Spalte zulassen, wird ein anderer Wert in der Spalte nur in einer Zeile angezeigt. Wie schaffen wir das? – Oscar

+0

siehe auch: http://Stackoverflow.com/q/1361340/4418 – warren

Antwort

341

Ich bin nicht wirklich darauf hindeutet, dass Sie dies tun, als UNIQUE Index wie von Piskvor vorgeschlagen und andere ist eine weit bessere Art und Weise, es zu tun, aber man kann tatsächlich tun, was Sie versucht haben:

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; 

Legen Sie einen Datensatz:

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 | 
+----+--------+-----------+------+ 

erneut versuchen, den gleichen Datensatz einfügen:

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 | 
+----+--------+-----------+------+ 

einen anderen Datensatz einfügen:

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 | 
+----+--------+-----------+------+ 

Und so weiter ...

+9

Danke, dass geholfen hat. Mein tatsächliches Problem ist viel komplexer und die Spalte kann einfach nicht eindeutig sein und ich kann mich nicht auf den Primärschlüssel verlassen. Aber genau das habe ich gesucht. – Rupert

+0

Das würde funktionieren, aber ich bin ein bisschen besorgt um die Leistung - es sei denn, es gibt einen Index für 'name', die innerste Auswahl ist schrecklich langsam. Wenn es einen Index gibt, sollte dies OK funktionieren. – Piskvor

+2

@ Piskovar: [email protected]: Sie sollten die Spalte, auf die in der inneren Select-Anweisung verwiesen wird (in diesem Fall 'name'), wenn überhaupt möglich indizieren. Beachte auch, dass du 'SELECT 'John', 'Doe', '022' FROM table_listnames 'anstelle von' SELECT * FROM (WÄHLEN 'John', 'Doe', '022') AS tmp 'wählen kannst - aber das wird funktioniert nur, wenn 'table_listnames' bereits eine oder mehrere Zeilen enthält. Ich bezweifle, dass die Geschwindigkeit anders ist, also ist es wahrscheinlich kein Problem. – Mike

2

Sie fügen nicht das Aktualisieren des Ergebnisses ein. Sie können die Namensspalte in der primären Spalte definieren oder festlegen, dass sie eindeutig ist.

+0

sache ist ich kann es nicht zu primären oder einzigartigen setzen – Rupert

216

INSERT doesn't allow WHERE in the syntax.

Was Sie tun können: Erstellen Sie eine UNIQUE INDEX auf dem Feld, die eindeutig sein sollte (name), dann verwenden Sie entweder:

  • normalen INSERT (und den Fehler behandeln, wenn der Name bereits vorhanden)
  • INSERT IGNORE (führt zu einer Warnung (anstelle eines Fehlers), wenn der Name bereits existiert)
  • INSERT ... ON DUPLICATE KEY UPDATE (die die UPDATE am Ende ausführt, wenn der Name bereits existiert, see documentation)
+8

Vielen Dank für die Auflistung der verfügbaren Optionen. INSERT IGNORE hat mir geholfen. – Xynariz

+14

Danke, 3.5 Jahre später und immer noch Menschen helfen :). – Andrew

+6

5 Jahre später und immer noch helfen ppl :) – motan

11

Wenn Sie wirklich keinen eindeutigen Index auf den Tisch bekommen, kann man versuchen, ...

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: Sie fast getroffen, aber Sie haben einen Fehler in Ihrer Synatx. Dein Einsatz wird niemals funktionieren. Getestet habe ich auf meine Datenbank und hier ist die richtige Antwort:

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' 

ich Ihnen mein Beispiel y Tabelle gebe. Insert ist fast das selbe wie Bian Hooper geschrieben hat, außer dass ich das SELECT FROM DUAL von einem anderen Tisch genommen habe. Cind Grüßen, Ivan

+2

Was ist das "Dual"? Ein eingebautes Keyword? Ich sehe einfach nicht den Unterschied zu dem, was Brian gesagt hat ... EDIT: Weitere Untersuchung wurde gemischt und widersprüchliche (?) Ergebnisse. Während auf der Seite [SQL DUAL table] (http://www.w3resource.com/sql/sql-dual-table.php) steht, dass MySQL keine DUAL-Tabellen unterstützt, ist das [MySQL-Handbuch] (http: //dev.mysql .com/doc/refman/5.0/de/select.html) sagt, dass es das tut. Mein eigener Test zeigt, dass dies nicht der Fall ist, da es 'unbekannte Tabellenstatus: TABLE_TYPE'-Nachrichten gibt, obwohl die Abfrage ein Ergebnis lieferte. Wahrscheinlich, weil MySQL die Klausel 'FROM DUAL' nicht benötigt? – not2qubit

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

Hier die mysql query, dass Insert Datensätze, wenn nicht vorhanden und wird bestehende ähnliche Datensätze ignorieren.

----Untested---- 
+4

es funktioniert nicht für mich, INSERT IGNORE IN emAssignedTagsForEvent SET eventId = '2', defaultTagId = '1'; – pitu

+6

Sieht aus wie eine Mischung aus Einfüge- und Aktualisierungssyntaxen. Meinst du "INSERT IGNORE IN" mytable "(' field0', 'field1',' field2') Werte ('2 ', 12345, 12678); ''? – Hobo

+0

@Hobo Von MySQL Handbuch https://dev.mysql.com/doc/refman/5.7/en/insert.html INSERT Syntax: Es kann 'INSERT [...] IGNORE IN MYTABLE VALUES ...' sein Oder 'INSERT [...] IGNORE IN mytable SET col_name = {expr | DEFAULT}, ... ' – Shirkam

37

Arbeitete:

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

Das funktioniert nur für Oracle-Datenbanken richtig?https://en.wikipedia.org/wiki/DUAL_table Diese Frage bezieht sich speziell auf MySQL! –

+0

Ich teste nicht in Oracle-Datenbank. Es funktioniert gut bei MySQL und getestet. –

+3

Ich seit "Dual" gelernt ist in MySQL verfügbar, aber nicht in MariaDB, der Open-Source-Zweig von MySQL –

10

ähnliches Problem zu überwinden, habe ich den Tisch Ich bin Einfügen einer eindeutigen Spalte haben, gemacht. Mit Ihrem Beispiel bei der Erstellung hätte ich so etwas wie:

name VARCHAR(20), 
UNIQUE (name) 

und dann die folgende Abfrage verwenden, wenn in sie einfügen:

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 ist eine Oracle-Tabelle nicht MySQL –

17

MySQL bietet eine sehr nette Lösung:

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

Sehr einfach zu verwenden, da Sie einen eindeutigen Primärschlüssel (hier mit Wert 5) deklariert haben.

+2

Aber es aktualisiert den Datensatz (siehe betroffenen Zeilen) – Azmeer

+0

zu verhindern, dass Sie erstellen müssen ein einzigartiger Index, mehr Info hier: [Link] (http://stackoverflow.com/questions/5835978/how-to-properly-create-composite-primary-keys-mysql) – Azmeer

2

ich ein Problem hatte, und das Verfahren Mike riet zum Teil arbeitete, hatte ich einen Fehler Dublettenspaltenname = ‚0‘, und verändert die Syntax der Abfrage als 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;"; 

Das Problem war, mit Spaltennamen. SUM3 war gleich SUM4 und mysql dublicate Spaltennamen throwed, und ich den Code in dieser Syntax geschrieben und es funktionierte perfekt,

+0

Lebensretter, thanks mate! – Areeb

5

Diese Abfrage funktioniert gut:

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 

Und Sie können die Tabelle mit folgenden Abfrage erstellen :

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 ; 

Hinweis: erstellen Tabelle zweiten Abfrage vor der ersten Abfrage verwenden möchten.

0

Ich hatte ein ähnliches Problem und ich musste mehrere einfügen, wenn nicht vorhanden. Also kam ich aus den obigen Beispielen zu dieser Kombination ... es ist hier, nur für den Fall, dass jemand es brauchen würde.

Hinweis: Ich musste überall Namen definieren, da MSSQL es brauchte ... MySQL arbeitet auch mit *.

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, PRIMARY KEY (OID), UNIQUE KEY name_UNIQUE (name) ) ENGINE = InnoDB AUTO_INCREMENT = 1;

oder

MSSQL: CREATE TABLE [Namen] ( [OID] INT IDENTITY (1, 1) NOT NULL, [name] NVARCHAR (32) NOT NULL, PRIMARY KEY CLUSTERED ([OID ] ASC) ); UNIQUE NONCLUSTERED INDEX ERSTELLEN [Index_Names_Name] ON [Namen] ([Name] ASC);

5

Sie können ganz einfach folgende Weise verwenden:

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

Auf diese Weise können Sie jede neue roh einfügen und wenn Sie doppelte Daten haben, ersetzen bestimmte Spalte (beste Spalte Zeitstempel).
Zum Beispiel:

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

Diese Abfrage kann in PHP-Code verwendet werden.

Ich habe eine ID-Spalte in der Tabelle, also muss ich für alle Spalten mit Ausnahme dieser ID-Spalte für die Vervielfältigung prüfen:

#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; 

und jetzt neues Element wird nur für den Fall hinzugefügt werden, von dort nicht ist vorhanden Zeile mit Werten konfiguriert in SET Zeichenfolge

Verwandte Themen