it-swarm.com.de

Wie füge ich in MySQL ein, wenn es das nicht gibt?

Ich begann mit dem Googeln und fand diesen Artikel , der über Mutex-Tabellen spricht.

Ich habe eine Tabelle mit ~ 14 Millionen Datensätzen. Wenn ich weitere Daten im gleichen Format hinzufügen möchte, kann sichergestellt werden, dass der einzufügende Datensatz nicht bereits vorhanden ist, ohne ein Abfragepaar zu verwenden (dh eine Abfrage zum Überprüfen und eine zum Einfügen ist die Ergebnismenge) leeren)?

Gewährleistet eine unique -Beschränkung für ein Feld, dass insert fehlschlägt, wenn es bereits vorhanden ist?

Es scheint, dass mit nur einer Einschränkung, wenn ich die Einfügung über PHP erteile, das Skript krächzt.

762
warren

benutze INSERT IGNORE INTO table

siehe http://bogdan.org.ua/2007/10/18/mysql-insert-if-not-exists-syntax.html

es gibt auch die INSERT … ON DUPLICATE KEY UPDATE -Syntax. Erklärungen finden Sie unter dev.mysql.com


Beitrag von bogdan.org.ua laut Googles Webcache :

18. Oktober 2007

Zum Anfang: Ab dem neuesten MySQL-Stand ist die im Titel angegebene Syntax nicht möglich. Es gibt jedoch mehrere sehr einfache Möglichkeiten, mit den vorhandenen Funktionen das zu erreichen, was erwartet wird.

Es gibt 3 mögliche Lösungen: mit INSERT IGNORE, REPLACE oder INSERT… ON DUPLICATE KEY UPDATE.

Stellen Sie sich vor, wir haben einen Tisch:

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, wir haben eine automatische Pipeline, die Transkriptions-Metadaten aus Ensembl importiert, und die Pipeline könnte aus verschiedenen Gründen bei jedem Ausführungsschritt unterbrochen werden. Daher müssen wir zwei Dinge sicherstellen: 1) Wiederholte Ausführungen der Pipeline zerstören unsere Datenbank nicht und 2) Wiederholte Ausführungen sterben nicht aufgrund von Fehlern aufgrund von "doppelten Primärschlüsseln".

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 vorhanden ist, wird er überschrieben. Wenn es noch nicht existiert, wird es erstellt. Diese Methode ist jedoch in unserem Fall nicht effizient: Sie müssen vorhandene Datensätze nicht überschreiben, sondern können sie einfach überspringen.

Methode 2: mit INSERT IGNORE Auch sehr 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). (Genauer gesagt, hier ein Zitat aus dem MySQL-Referenzhandbuch: „Wenn Sie das Schlüsselwort IGNORE verwenden, werden Fehler, die beim Ausführen der INSERT-Anweisung auftreten, stattdessen als Warnungen behandelt. Ohne IGNORE beispielsweise eine Zeile, die einen vorhandenen UNIQUE-Index dupliziert oder PRIMARY KEY-Wert in der Tabelle verursacht einen Doppelschlüsselfehler und die Anweisung wird abgebrochen. ”.) Wenn der Datensatz noch nicht vorhanden ist, wird er erstellt.

Diese zweite Methode weist mehrere potenzielle Schwachstellen auf, 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.

Es gibt noch eine weitere Option: Verwenden Sie die INSERT … ON DUPLICATE KEY UPDATE -Syntax und führen Sie im UPDATE-Teil einfach keine bedeutungslosen (leeren) Operationen aus, z um diesen Vorgang zu ignorieren). Vorteil dieser Methode ist, dass sie nur doppelte Schlüsselereignisse ignoriert und bei anderen Fehlern immer noch abbricht.

Als letzte Bemerkung: Dieser Beitrag wurde von Xaprb inspiriert. Ich empfehle außerdem, seinen anderen Beitrag zum Schreiben flexibler SQL-Abfragen zu lesen.

744
knittl

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) 

Erklärung:

Die innerste Abfrage

SELECT * FROM `table` 
      WHERE `value1`='stuff for value1' AND `value2`='stuff for value2' LIMIT 1

wird als WHERE NOT EXISTS-Bedingung verwendet, wird festgestellt, ob bereits eine Zeile mit den einzufügenden Daten vorhanden ist. Nachdem eine Zeile dieser Art gefunden wurde, wird die Abfrage möglicherweise beendet, daher kann der LIMIT 1 (Mikrooptimierung, kann weggelassen werden).

Die Zwischenabfrage

SELECT 'stuff for value1', 'stuff for value2' FROM DUAL

repräsentiert die einzufügenden Werte. 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 der Version 5.7.26 wurde beim Weglassen von FROM DUAL eine gültige Anfrage gestellt, aber ältere Versionen (wie 5.5.60) scheinen die FROM -Informationen zu erfordern. Mit WHERE NOT EXISTS gibt die Zwischenabfrage eine leere Ergebnismenge zurück, wenn die innerste Abfrage übereinstimmende Daten gefunden hat.

Die äußere Frage

INSERT INTO `table` (`value1`, `value2`) 

fügt die Daten ein, falls diese von der Zwischenabfrage zurückgegeben werden.

177
Server

bei doppeltem Schlüssel-Update oder Ignorieren einfügen können mit MySQL praktikable Lösungen sein.


Beispiel für bei doppeltem Schlüssel-Update Update basierend auf 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;

Beispiel für Ignorieren einfügen basierend auf 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] ... ]

Oder:

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] ... ]

Oder:

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name [(col_name,...)]
    SELECT ...
    [ ON DUPLICATE KEY UPDATE
      col_name=expr
        [, col_name=expr] ... ]
53
Zed

Jede einfache Einschränkung sollte den Job erledigen, wenn eine Ausnahme akzeptabel ist. Beispiele:

  • primärschlüssel, wenn kein Ersatzschlüssel
  • eindeutige Einschränkung für eine Spalte
  • mehrspaltige eindeutige Einschränkung

Tut mir leid, das scheint täuschend einfach zu sein. Ich weiß, dass es schlecht aussieht, wenn Sie den Link mit uns teilen. ;

Aber ich gebe diese Antwort nie ohne Grund, weil sie Ihr Bedürfnis zu erfüllen scheint. (Andernfalls wird möglicherweise die Aktualisierung Ihrer Anforderungen ausgelöst, was auch "eine gute Sache" (TM) wäre.).

--- (Bearbeitet: Wenn eine Einfügung die Datenbankeinschränkung aufheben würde, wird eine Ausnahme auf Datenbankebene ausgelöst, die vom Treiber weitergeleitet wird. Es wird sicherlich Ihr Skript stoppen, mit einem Fehler. In PHP muss es möglich sein, diesen Fall zu behandeln ...

24
KLE

Hier ist eine PHP -Funktion, die nur dann eine Zeile einfügt, wenn alle angegebenen Spaltenwerte noch nicht 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 haben, 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;
    }
    

Anwendungsbeispiel:

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

Wenn der Datensatz vorhanden ist, wird er überschrieben. Wenn es noch nicht existiert, wird es erstellt.

18
Rocio

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

Es gibt mehrere Antworten, die beschreiben, wie Sie dieses Problem lösen können, wenn Sie einen UNIQUE -Index haben, den Sie mit ON DUPLICATE KEY oder INSERT IGNORE überprüfen können. Dies ist nicht immer der Fall, und da UNIQUE eine Längenbeschränkung (1000 Byte) hat, können Sie dies möglicherweise nicht ändern. Zum Beispiel musste ich mit Metadaten in WordPress (wp_postmeta) arbeiten.

Ich habe es endlich mit zwei Fragen gelöst:

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 = ?);

Abfrage 1 ist eine reguläre UPDATE Abfrage, die keine Auswirkung hat, wenn der betreffende Datensatz nicht vorhanden ist. Abfrage 2 ist eine INSERT, die von einem NOT EXISTS abhängt, d. H. Die INSERT wird nur ausgeführt, wenn der Datensatz nicht vorhanden ist.

5
wortwart

Versuchen:

// 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
}

Oder Sie können tun:

// 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
    }
}

Diese Methode ist schnell und einfach. Zur Verbesserung der Geschwindigkeit der Abfrage in Ihrer großen Tabelle INDEX-Spalten 'xxx' (in meinem Beispiel).

4
Andrea php