Wie kopiert man einen Datensatz in eine SQL-Tabelle, tauscht aber die eindeutige ID der neuen Zeile aus?

123

Diese Frage kommt dem nahe, was ich brauche, aber mein Szenario ist etwas anders. Die Quell- und Zieltabelle sind identisch und der Primärschlüssel ist eine eindeutige Kennung (guid). Wenn ich das versuche:

insert into MyTable
    select * from MyTable where uniqueId = @Id;

Ich erhalte offensichtlich eine Verletzung der Primärschlüsseleinschränkung, da ich versuche, über den Primärschlüssel zu kopieren. Eigentlich möchte ich überhaupt nicht über den Primärschlüssel kopieren. Vielmehr möchte ich eine neue erstellen. Außerdem möchte ich bestimmte Felder selektiv kopieren und die anderen null lassen. Um die Sache komplexer zu gestalten, muss ich den Primärschlüssel des Originaldatensatzes in ein anderes Feld in der Kopie einfügen (Feld PreviousId).

Ich bin mir sicher, dass es eine einfache Lösung dafür gibt. Ich kenne einfach nicht genug TSQL, um zu wissen, was es ist.

Kilhoffer
quelle

Antworten:

186

Versuche dies:


insert into MyTable(field1, field2, id_backup)
    select field1, field2, uniqueId from MyTable where uniqueId = @Id;

Alle nicht angegebenen Felder sollten ihren Standardwert erhalten (der normalerweise NULL ist, wenn er nicht definiert ist).

AaronSieb
quelle
2
Genial. Lief wie am Schnürchen. Es war so offensichtlich, als Sie es ausgeschrieben haben. Vielen Dank!!
Kilhoffer
1
Dies funktioniert, wenn Sie nur wenige Spalten haben. Wenn Sie 20 oder 30 Spalten sagen, können Sie diese Methode trotzdem verwenden, aber es wäre entmutigend. Außerdem müssen Sie jedes Mal, wenn Sie eine Spalte hinzufügen und auch diese Daten kopieren möchten, die Spalte zu diesem Skript hinzufügen. Am besten generieren Sie Einfügungen dynamisch mithilfe von sys-Tabellen.
Jeyara
93

Ok, ich weiß, dass es ein altes Problem ist, aber ich poste trotzdem meine Antwort.

Ich mag diese Lösung. Ich muss nur die Identitätsspalte (n) angeben.

SELECT * INTO TempTable FROM MyTable_T WHERE id = 1;
ALTER TABLE TempTable DROP COLUMN id;
INSERT INTO MyTable_T SELECT * FROM TempTable;
DROP TABLE TempTable;

Die "id" -Spalte ist die Identitätsspalte und das ist die einzige Spalte, die ich angeben muss. Es ist sowieso besser als umgekehrt. :-)

Ich benutze SQL Server. Vielleicht möchten Sie " CREATE TABLE" und " UPDATE TABLE" in Zeile 1 und 2 verwenden. Hmm, ich habe gesehen, dass ich nicht wirklich die Antwort gegeben habe, die er wollte. Er wollte die ID auch in eine andere Spalte kopieren. Diese Lösung eignet sich jedoch zum Erstellen einer Kopie mit einer neuen Auto-ID.

Ich bearbeite meine Lösung mit den Ideen von Michael Dibbets.

use MyDatabase; 
SELECT * INTO #TempTable FROM [MyTable] WHERE [IndexField] = :id;
ALTER TABLE #TempTable DROP COLUMN [IndexField]; 
INSERT INTO [MyTable] SELECT * FROM #TempTable; 
DROP TABLE #TempTable;

Sie können mehr als eine Spalte löschen, indem Sie sie durch ein "," trennen. Die: id sollte durch die ID der Zeile ersetzt werden, die Sie kopieren möchten. MyDatabase, MyTable und IndexField sollten (natürlich) durch Ihre Namen ersetzt werden.

Jonas
quelle
1
Dies ist schwierig. Wie können Sie sicher sein, dass Sie während des INSERT INTO in Zeile 3 die richtige ID in die richtige Zeile kopieren?
Erno
Die ID-Spalte ist eine Identitätsspalte (in meiner Tabelle), daher ist mir der Wert egal. Ich möchte nur einen neuen Datensatz mit den gleichen Werten wie der "alte".
Jonas
9
Denn TempTablewäre es nicht zu verwenden besser sein #TempTable, so dass es eine wahre temporäre Tabelle ist?
Jess
3
Ich verwende dies im folgenden Format. Auf use MyDatabase; SELECT * INTO #TempTable FROM [TABLE] WHERE [indexfield] = :id; ALTER TABLE #TempTable DROP COLUMN [indexfield]; INSERT INTO [TABLE] SELECT * FROM #TempTable; DROP TABLE #TempTable;diese Weise weiß ich, dass es so schnell wie möglich ohne Verzögerungen beim Schreiben einer intermittierenden Datei auf die Disc bereinigt wird.
Tschallacka
3
Sie können auch verwenden, $identitywenn Sie Ihren Identitätsspaltennamen nicht fest codieren möchten
Factor Mystic
12

Ich vermute, Sie versuchen zu vermeiden, alle Spaltennamen aufzuschreiben. Wenn Sie SQL Management Studio verwenden, können Sie einfach mit der rechten Maustaste auf die Tabelle und das Skript als Einfügen klicken. Dann können Sie mit dieser Ausgabe herumspielen, um Ihre Abfrage zu erstellen.

Matt Hinze
quelle
10

Geben Sie alle Felder außer Ihrem ID-Feld an.

INSERT INTO MyTable (FIELD2, FIELD3, ..., FIELD529, PreviousId)
SELECT FIELD2, NULL, ..., FIELD529, FIELD1
FROM MyTable
WHERE FIELD1 = @Id;
Scott Bevington
quelle
6

Ich habe das gleiche Problem, bei dem ein einzelnes Skript mit einer Tabelle arbeiten soll, deren Spalten von anderen Entwicklern regelmäßig hinzugefügt werden. Darüber hinaus unterstütze ich viele verschiedene Versionen unserer Datenbank, da Kunden möglicherweise nicht alle mit der aktuellen Version auf dem neuesten Stand sind.

Ich habe die Lösung von Jonas genommen und leicht modifiziert. Auf diese Weise kann ich eine Kopie der Zeile erstellen und dann den Primärschlüssel ändern, bevor ich ihn wieder in die ursprüngliche Quelltabelle einfüge. Dies ist auch sehr praktisch, wenn Sie mit Tabellen arbeiten, die keine NULL-Werte in Spalten zulassen und nicht jeden Spaltennamen in INSERT angeben müssen.

Dieser Code kopiert die Zeile für 'ABC' nach 'XYZ'.

SELECT * INTO #TempRow FROM SourceTable WHERE KeyColumn = 'ABC';
UPDATE #TempRow SET KeyColumn = 'XYZ';
INSERT INTO SourceTable SELECT * FROM #TempRow;
DELETE #TempRow;

Sobald Sie fertig sind, legen Sie die temporäre Tabelle ab.

DROP TABLE #TempRow;
TonyT
quelle
4

Ich weiß, dass meine Antwort zu spät zur Party kommt. Aber die Art und Weise, wie ich es gelöst habe, ist etwas anders als alle Antworten.

Ich hatte eine Situation, ich muss eine Zeile in einer Tabelle mit Ausnahme weniger Spalten klonen. Diese wenigen werden neue Werte haben. Dieser Prozess sollte zukünftige Änderungen an der Tabelle automatisch unterstützen. Dies bedeutet, dass Sie den Datensatz klonen müssen, ohne Spaltennamen anzugeben.

Mein Ansatz ist,

  1. Fragen Sie Sys.Columns ab, um die vollständige Liste der Spalten für die Tabelle abzurufen und die Namen der Spalten anzugeben, die in der where-Klausel übersprungen werden sollen.
  2. Konvertieren Sie das in CSV als Spaltennamen.
  3. Build Select ... In dieses Skript einfügen.


declare @columnsToCopyValues varchar(max), @query varchar(max)
SET @columnsToCopyValues = ''

--Get all the columns execpt Identity columns and Other columns to be excluded. Say IndentityColumn, Column1, Column2 Select @columnsToCopyValues = @columnsToCopyValues + [name] + ', ' from sys.columns c where c.object_id = OBJECT_ID('YourTableName') and name not in ('IndentityColumn','Column1','Column2') Select @columnsToCopyValues = SUBSTRING(@columnsToCopyValues, 0, LEN(@columnsToCopyValues)) print @columnsToCopyValues

Select @query = CONCAT('insert into YourTableName (',@columnsToCopyValues,', Column1, Column2) select ', @columnsToCopyValues, ',''Value1'',''Value2'',', ' from YourTableName where IndentityColumn =''' , @searchVariable,'''')

print @query exec (@query)

Jeyara
quelle
2
insert into MyTable (uniqueId, column1, column2, referencedUniqueId)
select NewGuid(), // don't know this syntax, sorry
  column1,
  column2,
  uniqueId,
from MyTable where uniqueId = @Id
Jeffrey L Whitledge
quelle
1

Wenn "Schlüssel" Ihr PK-Feld ist und es automatisch numerisch ist.

insert into MyTable (field1, field2, field3, parentkey)
select field1, field2, null, key from MyTable where uniqueId = @Id

Es wird ein neuer Datensatz generiert, wobei Feld1 und Feld2 aus dem ursprünglichen Datensatz kopiert werden

Eduardo Campañó
quelle
1

Meine Tabelle enthält 100 Felder, und ich brauchte eine Abfrage, um einfach zu funktionieren. Jetzt kann ich eine beliebige Anzahl von Feldern mit einer grundlegenden bedingten Logik ausschalten und mich nicht um ihre Ordnungsposition kümmern.

  1. Ersetzen Sie den folgenden Tabellennamen durch Ihren Tabellennamen

    SQLcolums = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE (TABLE_NAME = 'TABLE-NAME')"
    
    Set GetColumns = Conn.Execute(SQLcolums)
    Do WHILE not GetColumns.eof
    
    colName = GetColumns("COLUMN_NAME")
  2. Ersetzen Sie den ursprünglichen Identitätsfeldnamen durch Ihren PK-Feldnamen

    IF colName = "ORIGINAL-IDENTITY-FIELD-NAME" THEN ' ASSUMING THAT YOUR PRIMARY KEY IS THE FIRST FIELD DONT WORRY ABOUT COMMAS AND SPACES
        columnListSOURCE = colName 
        columnListTARGET = "[PreviousId field name]"
    ELSE
        columnListSOURCE = columnListSOURCE & colName
        columnListTARGET = columnListTARGET & colName
    END IF
    
    GetColumns.movenext
    
    loop
    
    GetColumns.close    
  3. Ersetzen Sie die Tabellennamen erneut (sowohl den Namen der Zieltabelle als auch den Namen der Quelltabelle). Bearbeiten Sie Ihre whereBedingungen

    SQL = "INSERT INTO TARGET-TABLE-NAME (" & columnListTARGET & ") SELECT " & columnListSOURCE & " FROM SOURCE-TABLE-NAME WHERE (FIELDNAME = FIELDVALUE)" 
    Conn.Execute(SQL)
Rit Man
quelle
0

Sie können dies tun:

INSERT INTO DENI/FRIEN01P 
SELECT 
   RCRDID+112,
   PROFESION,
   NAME,
   SURNAME,
   AGE, 
   RCRDTYP, 
   RCRDLCU, 
   RCRDLCT, 
   RCRDLCD 
FROM 
   FRIEN01P      

Dort sollten Sie anstelle von 112 eine Nummer der maximalen ID in die Tabelle DENI / FRIEN01P eintragen.

Denis Kutlubaev
quelle
0

Hier ist, wie ich es mit ASP classic gemacht habe und es mit den obigen Antworten nicht ganz zum Laufen bringen konnte. Ich wollte in der Lage sein, ein Produkt in unserem System in eine neue product_id zu kopieren und brauchte es, um auch dann funktionieren zu können Fügen Sie der Tabelle weitere Spalten hinzu.

Cn.Execute("CREATE TEMPORARY TABLE temprow AS SELECT * FROM product WHERE product_id = '12345'")
Cn.Execute("UPDATE temprow SET product_id = '34567'")
Cn.Execute("INSERT INTO product SELECT * FROM temprow")
Cn.Execute("DELETE temprow")
Cn.Execute("DROP TABLE temprow")
Daniel Nordh
quelle
Ich glaube nicht, dass Sie 5 separate SQL-Befehle ausgeben müssen, um dies zu vervollständigen. Und wen bestimmen Sie im 2. Befehl, dass die Produkt-ID 34567 sein sollte?
Jeyara
34567 ist nur ein Beispiel. Sie können es auf eine Variable oder was auch immer Sie wollen setzen. Wenn Sie dies in ASP Classic besser tun können, lassen Sie es mich wissen. :)
Daniel Nordh
Sie könnten einen gespeicherten Prozess schreiben, um alle diese in einer Zeile auszuführen. Außerdem war PK normalerweise ein automatischer Inkrementierungswert. Sich selbst zuzuweisen ist also keine gute Idee.
Jeyara
Wie würden Sie das Verfahren schreiben? Bitte erleuchte mich. PK? Wenn Sie Artikel-IDs meinen, verwenden wir in unserem System Artikel-IDs basierend auf dem Geschäft, in dem wir sie verkaufen. Zum Beispiel haben alle unsere Spielwarengeschäfte eine Artikelnummer, die mit 30 beginnt, und unser Sportgeschäft beginnt mit 60. Außerdem sparen wir Platz, damit wir Holen Sie sich eine neue Farbe in, zum Beispiel können wir eine Artikel-ID neben den anderen der gleichen Art haben. Wie gesagt, dies war meine Lösung, die in unserem System funktioniert. Wie Sie Variablen setzen, ist nicht so wichtig und die meisten Programmierer würden verstehen, was für sie und ihr System funktioniert.
Daniel Nordh
PK steht für Primärschlüssel. In Ihrem Fall ist es '12345'. Unter stackoverflow.com/questions/21561657/… erfahren Sie, wie Sie gespeicherte Prozesse in Classic ASP verwenden, wenn Sie nicht wissen, wie. Verschieben Sie dazu alle in einen gespeicherten Prozess und übergeben Sie Ihren '12345' als Parameter. Die Art und Weise, wie Sie arbeiten würden, aber parametrisierte Skripte werden heutzutage empfohlen.
Jeyara