PHP MySQL Kopieren Sie eine Zeile innerhalb derselben Tabelle … mit einem Primär- und einem eindeutigen Schlüssel

Lesezeit: 8 Minuten

Meine Tabelle hat zwei Schlüssel, einer ist eine automatisch inkrementierende ID (PRIMARY), der andere ist der Name des Elements (UNIQUE).

Ist es möglich, eine Zeile innerhalb derselben Tabelle zu duplizieren? Ich habe versucht:

INSERT INTO items
SELECT * FROM items WHERE id = '9198'

Das gibt den Fehler Duplicate entry '9198' for key 'PRIMARY'

Ich habe auch versucht:

INSERT INTO items
SELECT * FROM items WHERE id = '9198'
ON DUPLICATE KEY UPDATE id=id+1

Was den Fehler gibt Column 'id' in field list is ambiguous

Und was das Feld Artikelname (UNIQUE) betrifft, gibt es eine Möglichkeit zum Anhängen (Copy) zum Artikelnamen, da auch dieses Feld eindeutig sein muss?

  • Versuchen Sie, alle Zeilen außer der ID auszuwählen, vorausgesetzt, Ihre ID ist automatisch inkrementiert, sie wird automatisch aktualisiert.

    – Datenbyss

    26. Juli 2012 um 1:04 Uhr

  • @databyss Das würde funktionieren, aber ich suche nach einer alternativen Methode, da diese Tabelle ein paar hundert Spalten hat.

    – Nordisch

    26. Juli 2012 um 1:05 Uhr

  • Kopieren Sie die Spaltennamen und fügen Sie sie ein.

    – Datenbyss

    26. Juli 2012 um 1:06 Uhr

  • ein paar hundert Spalten? Es muss höllisch sein, so viele Spalten in einer einzigen Tabelle zu verwalten!

    – Jocelyn

    26. Juli 2012 um 1:06 Uhr

  • Sie KÖNNEN die Spaltennamen mit “SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name = ‘items’ and column_name <> ‘id'” abfragen.

    – Datenbyss

    26. Juli 2012 um 1:13 Uhr


Wählen Sie alle Spalten explizit aus, mit Ausnahme der ID-Spalte:

INSERT INTO items
(col1, col2, ..., coln)
SELECT col1, col2, ..., coln
FROM items
WHERE id = '9198'

Ihre nächste Frage wird wahrscheinlich sein:

Gibt es eine Möglichkeit, dies zu tun, ohne alle Spalten explizit aufzulisten?

Antwort: Nein, das glaube ich nicht.

  • In der Antwort von @ Mark finden Sie eine Möglichkeit, dies zu tun, ohne die Spalten explizit aufzulisten.

    – Michael LB

    21. Januar 2016 um 14:24 Uhr

  • Bei all den großartigen Dingen, die MySQL leistet, ist es wirklich ärgerlich, dass dies nicht irgendwie eine eingebaute Funktion ist. Beschränken Sie es auf PrimaryKey, inkrementieren Sie Setups automatisch, wenn dies erforderlich ist, aber trotzdem. Sie würden nicht denken, dass so etwas wie INSERT INTO table SELECT * FROM table WHERE primaryid = ‘x’ nicht automatisch erkannt werden könnte, da das PrimaryKey-Feld entfernt wird, aber alles andere kopiert wird. Oh, nun, MySQL ist immer noch erstaunlich, und ich nehme an, was es ist.

    – Andy Borgmann

    16. April 2020 um 17:01 Uhr

  • es funktioniert nicht. #1241 – Operand sollte 1 Spalte(n) enthalten

    – Eugen Kapustin

    27. September 2021 um 17:19 Uhr

Benutzeravatar von Phius
Phius

wenn du Ja wirklich Wenn Sie nicht alle Tabellenspalten wie in Marks Antwort auflisten möchten, können Sie Folgendes versuchen:

CREATE TEMPORARY TABLE temp_tbl SELECT * FROM items WHERE id = '9198';
SELECT @maxId := MAX(id) + 1 FROM items;
UPDATE temp_tbl SET id = @maxId;
INSERT INTO items SELECT * FROM temp_tbl;
DROP TABLE temp_tbl;

Nicht schön, nicht schnell. Aber funktioniert.

  • Dieses Beispiel hat bei mir funktioniert. Ich habe nur dafür gesorgt, dass ich bei der Verwendung mit mehreren Benutzern einen zusätzlichen Teil zu temp_tbl hinzugefügt habe, damit er für diesen Benutzer eindeutig ist. Ich habe auch die folgende Zeile hinzugefügt: UPDATE temp_tbl SET field_that_needs_to_use_a_title = CONCAT(‘DUPLICATE ‘,field_that_needs_to_use_a_title) WHERE id = ‘9198’;

    – vr_driver

    19. Oktober 2013 um 4:43 Uhr

  • Dies würde nicht immer funktionieren – zB wenn die geklonte ID nicht die größte ID in der ursprünglichen Tabelle ist?

    – Elendurwen

    21. März 2019 um 11:01 Uhr

  • @Elendurwen In der Tat. Bearbeitet, damit es in dieser Situation funktioniert.

    – Phios

    21. März 2019 um 15:16 Uhr

Vielen Dank an Hobailey für die Bereitstellung einer großartigen wartungsfreien Lösung.

Hier ist der Code, den ich letztendlich verwendet habe und der für MySQLi aktualisiert wurde:

// Get the columns
$cols = array();
$result = $mysqli->query("SHOW COLUMNS FROM [TABLE]"); // Change table name

while ($r = $result->fetch_array(MYSQLI_ASSOC)) {
    if (!in_array($r["Field"], array("COLA", "COL4", "COL8"))) { // Edit array with any column names you want to exclude
        $cols[] = $r["Field"];
    }
}

// Build and do the insert
$result = $mysqli->query("SELECT * FROM [TABLE] WHERE [SELECTION CRITERIA];"); // Change table name and add selection criteria

while ($r = $result->fetch_array(MYSQLI_ASSOC)) {

    $insertSQL = "INSERT INTO [TABLE] (" . implode(", ",$cols) . ") VALUES ("; // Change table name
    $count = count($cols);

    foreach($cols as $counter=>$col) {
// This is where you can add any code to change the value of existing columns
        $insertSQL .= "'" . $mysqli->real_escape_string($r[$col]) . "'";
        if ($counter < ($count - 1)) {
            $insertSQL .= ", ";
        }
    } // END foreach

    $insertSQL .= ");";

    $mysqli->query($insertSQL);
    if ($mysqli->affected_rows < 1) {
// Add code if the insert fails
    } else {
// Add code if the insert is successful
    }

} // END while

  • Nicht schön, aber macht den Job! Ist die Linie $mysqli->real_escape_string($r[$col]) notwendig, wenn man bedenkt, dass die Werte bereits in der Datenbank sind?

    – Michael LB

    21. Januar 2016 um 14:22 Uhr


  • Ja, Escape ist erforderlich – versuchen Sie es mit Anführungszeichen im Text – oder verwenden Sie PDO /bound params

    – ein alter Stempel

    28. Februar 2017 um 11:30 Uhr

Alternativ können Sie, wenn Sie nicht alle Spalten explizit schreiben möchten (und nicht mit dem Erstellen/Löschen von Tabellen beginnen möchten), einfach die Spalten der Tabelle abrufen und die Abfrage automatisch erstellen:

//get the columns
$cols=array();
$result = mysql_query("SHOW COLUMNS FROM [table]"); 
 while ($r=mysql_fetch_assoc($result)) {
  if (!in_array($r["Field"],array("[unique key]"))) {//add other columns here to want to exclude from the insert
   $cols[]= $r["Field"];
  } //if
}//while

//build and do the insert       
$result = mysql_query("SELECT * FROM [table] WHERE [queries against want to duplicate]");
  while($r=mysql_fetch_array($result)) {
    $insertSQL = "INSERT INTO [table] (".implode(", ",$cols).") VALUES (";
    $count=count($cols);
    foreach($cols as $counter=>$col) {
      $insertSQL .= "'".$r[$col]."'";
  if ($counter<$count-1) {$insertSQL .= ", ";}//dont want a , on the last one
    }//foreach
  $insertSQL .= ")";

  mysql_query($insertSQL);//execute the query
  }//while

Beachten Sie, dass dies den veralteten Code von MySQL verwendet und MySQLi sein sollte. Ich bin sicher, es könnte auch verbessert werden, aber es ist das, was ich benutze und es funktioniert sehr gut.

Der Fragetitel gibt an, dass Sie dies von PHP aus tun möchten.

Ich bin auf das gleiche Problem gestoßen und das Ausschreiben aller Spaltennamen ist mühsam und schwer zu pflegen, wenn Sie Ihre Tabellenstruktur ändern (Spalten hinzufügen/entfernen) … und ich mag die Lösungen nicht, die temporäre Tabellen verwenden.

Ich habe mich entschieden, dieses Problem mit zwei von PHP gesendeten Abfragen zu lösen – funktioniert großartig und erfordert keine Wartung (Haftungsausschluss: Ich verwende die meekrodb-Bibliothek für den Datenbankzugriff):

//get the data as an associative array
$row = DB::queryFirstRow("SELECT * FROM your_table WHERE id=%i",$id);
if ($row){
    unset($row["id"]); //unset the primary key
    DB::insert("your_table",$row);
    return DB::insertId();
} else {
    return false;
}

Sie können sogar weitere Manipulationen an den internen Daten vornehmen (andere Spalten zum Ignorieren aufheben, Werte bearbeiten usw.), bevor Sie sie erneut einfügen.

Benutzeravatar von Oliver-xx
Oliver-xx

Eine andere Lösung in PHP zum Kopieren einer Zeile in dieselbe Tabelle ohne bestimmte Spalte(n) / zB Primärschlüssel – und ohne “TEMPORARY TABLE” und “SHOW COLUMNS FROM…”-Methode:

$stmt = $db->prepare("select * from table where id = :id;");
$stmt->bindValue(':id', $_GET['id'], PDO::PARAM_INT);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
unset($row['id']);      //remove primary key

$columns = array_keys($row);
$query = "insert into table (`".implode('`, `', $columns)."`) select `".implode('`, `', $columns)."` from  data_ticket_serie where id = ".$_GET['id'].";";
// echo $query;
$stmt = $db->prepare($query);
$stmt->execute();

Das INSERT ist ein SELECT-Statement, also stehen die Werte nicht direkt im Statement –> keine Probleme mit “real_escape_string” oder ähnlichem.

Benutzeravatar von rockdaboot
rockdaboot

Für Tabellen mit vielen Spalten verwende ich eine (ja, langsame) Methode ähnlich der Phius-Idee.

Ich habe es nur der Vollständigkeit halber hier eingefügt.

Nehmen wir an, die Tabelle ‘tbl’ hat eine ‘id’, die wie definiert ist

id INT NOT NULL AUTO_INCREMENT PRIMARY KEY

Dann können Sie eine Zeile klonen/kopieren, indem Sie diesen Schritten folgen:

  1. Erstellen Sie eine tmp-Tabelle

VORLÄUFIGE TABELLE ERSTELLEN tbl_tmp WIE tbl;

  1. Fügen Sie einen oder mehrere Einträge ein, die Sie klonen/kopieren möchten

INSERT INTO tbl_tmp SELECT * FROM tbl WO …;

  1. Entfernen Sie das AUTOINCREMENT-Tag aus „id“.

ALTER TABLE tbl_tmp ÄNDERN ID INT;

  1. Löschen Sie den Primärindex

ALTER TABLE tbl_tmp DROP PRIMARY KEY;

  1. Aktualisieren Sie Ihre eindeutigen Indizes und setzen Sie „id“ auf 0 (0 wird für Schritt 6 benötigt, um zu funktionieren).

UPDATE tbl_tmp SET unique_value=?,id=0;

  1. Kopieren Sie Ihre geänderten Zeilen in „tbl“, wobei „id“ automatisch generiert wird.

INSERT INTO tbl SELECT * FROM tbl_tmp;

  1. Bereinigung (oder einfach die DB-Verbindung schließen)

DROP-TABELLE tbl_tmp;

Wenn Sie auch einige abhängige Daten in anderen Tabellen klonen/kopieren müssen, führen Sie die obigen Schritte für jede Zeile aus. Nach Schritt 6 können Sie den zuletzt eingefügten Schlüssel abrufen und diesen verwenden, um die abhängigen Zeilen in anderen Tabellen mit demselben Verfahren zu klonen/kopieren.

1440080cookie-checkPHP MySQL Kopieren Sie eine Zeile innerhalb derselben Tabelle … mit einem Primär- und einem eindeutigen Schlüssel

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy