Ich habe eine Tabelle mit ~14 Millionen Datensätzen. Wenn ich weitere Daten im gleichen Format hinzufügen möchte, gibt es eine Möglichkeit sicherzustellen, dass der einzufügende Datensatz nicht bereits existiert, ohne ein Abfragepaar zu verwenden (d. h. eine zu prüfende und eine einzufügende Abfrage ist die Ergebnismenge leer)?
Tut ein unique Beschränkung auf ein Feld garantieren die insert wird fehlschlagen, wenn es bereits da ist?
Es scheint, dass mit nur eine Einschränkung, wenn ich das Insert per PHP ausführe, krächzt das Skript.
Siehe stackoverflow.com/questions/44550788/… für Diskussionen darüber, wie man auto_inc-Werte nicht brennt.
– Rick James
29. Juni 2017 um 14:13 Uhr
@RickJames – das ist eine interessante Frage … aber nicht sicher, ob es direkt mit dieser Frage zusammenhängt 🙂
– Warren
29. Juni 2017 um 14:29 Uhr
Es wurde in einem Kommentar erwähnt, und diese andere Frage behauptete, diese Frage sei ein “exaktes Duplikat”. Daher hielt ich es für eine gute Idee, die Fragen zum Nutzen anderer miteinander zu verknüpfen.
– Rick James
29. Juni 2017 um 17:13 Uhr
Oh, ich denke nie daran, auf die Seitenleiste zu schauen.
Zum Anfang: Ab dem neuesten MySQL ist die im Titel dargestellte Syntax nicht möglich. Es gibt jedoch mehrere sehr einfache Möglichkeiten, um das zu erreichen, was mit vorhandener Funktionalität erwartet wird.
Es gibt 3 mögliche Lösungen: Verwenden von INSERT IGNORE, REPLACE oder INSERT … ON DUPLICATE KEY UPDATE.
Stellen Sie sich vor, wir haben eine Tabelle:
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;
Stellen Sie sich nun vor, dass wir eine automatische Pipeline haben, die Transkript-Metadaten aus Ensembl importiert, und dass die Pipeline aus verschiedenen Gründen bei jedem Ausführungsschritt unterbrochen werden könnte. Daher müssen wir zwei Dinge sicherstellen:
wiederholte Ausführungen der Pipeline zerstören unsere > Datenbank nicht
Wiederholte Ausführungen sterben nicht aufgrund von Fehlern „Duplizieren > Primärschlüssel“.
Methode 1: Verwenden von REPLACE
Es ist sehr einfach:
REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
Wenn der Datensatz existiert, wird er überschrieben; wenn es noch nicht existiert, wird es erstellt. Die Verwendung dieser Methode ist jedoch in unserem Fall nicht effizient: Wir müssen vorhandene Datensätze nicht überschreiben, es ist in Ordnung, sie einfach zu überspringen.
Methode 2: mit INSERT IGNORE Auch ganz einfach:
INSERT IGNORE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
Wenn die ‘ensembl_transcript_id’ bereits in der Datenbank vorhanden ist, wird sie stillschweigend übersprungen (ignoriert). (Um genauer zu sein, hier ein Zitat aus dem MySQL-Referenzhandbuch: „Wenn Sie das IGNORE-Schlüsselwort verwenden, werden Fehler, die während der Ausführung der INSERT-Anweisung auftreten, stattdessen als Warnungen behandelt. Zum Beispiel ohne IGNORE eine Zeile, die einen vorhandenen UNIQUE-Index dupliziert oder PRIMARY KEY-Wert in der Tabelle verursacht einen Duplicate-Key-Fehler und die Anweisung wird abgebrochen.”.) Wenn der Datensatz noch nicht existiert, wird er erstellt.
Diese zweite Methode hat mehrere potenzielle Schwächen, einschließlich des Nichtabbruchs der Abfrage, falls ein anderes Problem auftritt (siehe Handbuch). Daher sollte es verwendet werden, wenn es zuvor ohne das Schlüsselwort IGNORE getestet wurde.
Methode 3: Verwenden von INSERT … ON DUPLICATE KEY UPDATE:
Die dritte Option ist die Verwendung INSERT … ON DUPLICATE KEY UPDATE
Syntax, und im UPDATE-Teil tun Sie einfach nichts, führen Sie eine bedeutungslose (leere) Operation aus, wie die Berechnung von 0+0 (Geoffray schlägt vor, die id=id-Zuweisung für die MySQL-Optimierungs-Engine vorzunehmen, um diese Operation zu ignorieren). Vorteil dieser Methode ist, dass sie nur doppelte Tastenereignisse ignoriert und trotzdem bei anderen Fehlern abbricht.
Als letzte Anmerkung: Dieser Beitrag wurde von Xaprb inspiriert. Ich würde auch raten, seinen anderen Beitrag zum Schreiben flexibler SQL-Abfragen zu konsultieren.
und kann ich das mit “delayed” kombinieren, um das Skript zu beschleunigen?
– Warren
1. September 2009 um 9:18 Uhr
Ja, das verzögerte Einfügen könnte die Dinge für Sie beschleunigen. Versuch es
INSERT … ON DUPLICATE KEY UPDATE ist besser, da es die Zeile nicht löscht und keine erhält auto_increment Spalten und andere Daten.
– duftend
11. Dezember 2012 um 18:02 Uhr
Nur um alle zu informieren. Verwenden INSERT … ON DUPLICATE KEY UPDATE -Methode erhöht jede AUTO_INCREMENT-Spalte mit fehlgeschlagener Einfügung. Wahrscheinlich, weil es nicht wirklich gescheitert ist, sondern AKTUALISIERT wurde.
– not2qubit
29. Oktober 2013 um 21:36 Uhr
Server
Lösung:
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)
Erläuterung:
Die innerste Frage
SELECT * FROM `table`
WHERE `value1`='stuff for value1' AND `value2`='stuff for value2' LIMIT 1
verwendet als die WHERE NOT EXISTS-condition erkennt, ob bereits eine Zeile mit einzufügenden Daten existiert. Nachdem eine Zeile dieser Art gefunden wurde, kann die Abfrage beendet werden, daher die LIMIT 1 (Mikrooptimierung, kann weggelassen werden).
Die Zwischenabfrage
SELECT 'stuff for value1', 'stuff for value2' FROM DUAL
stellt die einzufügenden Werte dar. DUAL bezieht sich auf eine spezielle Tabelle mit einer Zeile und einer Spalte, die standardmäßig in allen Oracle-Datenbanken vorhanden ist (siehe https://en.wikipedia.org/wiki/DUAL_table). Auf einem MySQL-Server Version 5.7.26 bekam ich beim Auslassen eine gültige Abfrage FROM DUALaber ältere Versionen (wie 5.5.60) scheinen das zu erfordern FROM Information. Durch die Nutzung WHERE NOT EXISTS Die Zwischenabfrage gibt eine leere Ergebnismenge zurück, wenn die innerste Abfrage übereinstimmende Daten gefunden hat.
Die äußere Abfrage
INSERT INTO `table` (`value1`, `value2`)
fügt die Daten ein, falls welche von der Zwischenabfrage zurückgegeben werden.
kannst du ein paar mehr infos geben wie man das benutzt?
– Alex v
15. Mai 2012 um 19:02 Uhr
Diese Variante eignet sich, wenn kein eindeutiger Schlüssel auf Tabelle existiert (INSERT IGNORE und INSERT ON DUPLICATE KEY erfordern eindeutige Schlüsseleinschränkungen)
– rabudde
4. April 2013 um 18:29 Uhr
Wenn Sie in Zeile 2 “from dual” anstelle von “from table” verwenden, benötigen Sie die Klausel “limit 1” nicht.
– Reich
7. Mai 2013 um 15:41 Uhr
Was, wenn stuff for value1 und stuff for value2 sind identisch? Dies würde a werfen Duplicate column name
– Robin
29. Juni 2014 um 8:13 Uhr
Anstelle von DUAL können Sie (zumindest in mysql) INSERT INTO verwenden table (value1, value2) SELECT ‘Zeug für Wert1’, ‘Zeug für Wert2’ FROM (select 1) x WHERE NOT EXISTS (SELECT * FROM table WHERE Wert1=’Zeug für Wert1′ UND Wert2=’Zeug für Wert2′);
Jede einfache Einschränkung sollte die Aufgabe erfüllen, wenn eine Ausnahme akzeptabel ist. Beispiele:
Primärschlüssel, wenn kein Ersatz
Unique Constraint für eine Spalte
Eindeutigkeitsbedingung für mehrere Spalten
Entschuldigung, wenn dies täuschend einfach erscheint. Ich weiß, es sieht schlecht aus angesichts des Links, den Sie mit uns teilen. ;-(
Aber ich gebe trotzdem diese Antwort, weil sie Ihren Bedarf zu decken scheint. (Falls nicht, kann dies dazu führen, dass Sie Ihre Anforderungen aktualisieren, was ebenfalls „eine gute Sache“(TM) wäre).
Wenn eine Einfügung die Eindeutigkeitsbeschränkung der Datenbank verletzen würde, wird auf Datenbankebene eine Ausnahme ausgelöst, die vom Treiber weitergeleitet wird. Es wird sicherlich Ihr Skript mit einem Fehler stoppen. In PHP muss es möglich sein, diesen Fall zu adressieren …
Jebs
Versuche Folgendes:
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
Versuche dies Antworten sind auf StackOverflow von geringem Wert, da sie sehr wenig dazu beitragen, das OP und Tausende von zukünftigen Forschern zu schulen. Bitte bearbeiten Sie diese Antwort, um anzugeben, wie die Lösung funktioniert und warum sie eine gute Idee ist.
– mickmackusa
1. September 2018 um 2:58 Uhr
Perfekte Lösung für den Fall, dass die passenden Felder keine Schlüssel sind ..!
– Löwe
3. Februar 2020 um 22:19 Uhr
Rocio
REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
Wenn der Datensatz existiert, wird er überschrieben; wenn es noch nicht existiert, wird es erstellt.
Versuche dies Antworten sind auf StackOverflow von geringem Wert, da sie sehr wenig dazu beitragen, das OP und Tausende von zukünftigen Forschern zu schulen. Bitte bearbeiten Sie diese Antwort, um anzugeben, wie die Lösung funktioniert und warum sie eine gute Idee ist.
– mickmackusa
1. September 2018 um 2:58 Uhr
Perfekte Lösung für den Fall, dass die passenden Felder keine Schlüssel sind ..!
– Löwe
3. Februar 2020 um 22:19 Uhr
Peter Mortensen
Hier ist eine PHP-Funktion, die nur dann eine Zeile einfügt, wenn nicht alle angegebenen Spaltenwerte bereits in der Tabelle vorhanden sind.
Wenn sich eine der Spalten unterscheidet, wird die Zeile hinzugefügt.
Wenn die Tabelle leer ist, wird die Zeile hinzugefügt.
Wenn eine Zeile vorhanden ist, in der alle angegebenen Spalten die angegebenen Werte aufweisen, wird die Zeile nicht hinzugefügt.
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;
}
Ziemlich teuer, wenn Sie eine riesige Menge an Einfügungen haben.
– Eyad Fallatah
11. März 2012 um 2:41 Uhr
wahr, aber effizient, wenn Sie bestimmte Untersuchungen hinzufügen müssen
– Karl Wald
11. April 2012 um 19:44 Uhr
Warnung:mysql_* Die Erweiterung ist ab PHP 5.5.0 veraltet und wurde ab PHP 7.0.0 entfernt. Stattdessen entweder die mysql oder PDO_MySQL Erweiterung verwendet werden soll. Siehe auch die MySQL-API-Übersicht für weitere Hilfe bei der Auswahl einer MySQL-API.
– Dharman
20. März 2020 um 18:00 Uhr
9934100cookie-checkWie kann ich in MySQL “einfügen, wenn nicht vorhanden” ausführen?yes
dev.mysql.com/doc/refman/5.0/en/if.html
– Uğur Gümüşhan
8. April 2013 um 8:25 Uhr
Siehe stackoverflow.com/questions/44550788/… für Diskussionen darüber, wie man auto_inc-Werte nicht brennt.
– Rick James
29. Juni 2017 um 14:13 Uhr
@RickJames – das ist eine interessante Frage … aber nicht sicher, ob es direkt mit dieser Frage zusammenhängt 🙂
– Warren
29. Juni 2017 um 14:29 Uhr
Es wurde in einem Kommentar erwähnt, und diese andere Frage behauptete, diese Frage sei ein “exaktes Duplikat”. Daher hielt ich es für eine gute Idee, die Fragen zum Nutzen anderer miteinander zu verknüpfen.
– Rick James
29. Juni 2017 um 17:13 Uhr
Oh, ich denke nie daran, auf die Seitenleiste zu schauen.
– Rick James
29. Juni 2017 um 17:16 Uhr