Come si copia un record in una tabella SQL ma si scambia l'ID univoco della nuova riga?


123

Questa domanda si avvicina a ciò di cui ho bisogno, ma il mio scenario è leggermente diverso. La tabella di origine e la tabella di destinazione sono le stesse e la chiave primaria è un identificatore univoco (guid). Quando provo questo:

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

Ovviamente ottengo una violazione del vincolo di chiave primaria, poiché sto tentando di copiare sulla chiave primaria. In realtà, non voglio affatto copiare la chiave primaria. Piuttosto, voglio crearne uno nuovo. Inoltre, vorrei copiare selettivamente su determinati campi e lasciare gli altri nulli. Per rendere le cose più complesse, devo prendere la chiave primaria del record originale e inserirla in un altro campo nella copia (campo PreviousId).

Sono sicuro che ci sia una soluzione semplice a questo, semplicemente non conosco abbastanza TSQL per sapere di cosa si tratta.

Risposte:


186

Prova questo:


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

Tutti i campi non specificati dovrebbero ricevere il loro valore predefinito (che di solito è NULL quando non è definito).


2
Eccezionale. Ha funzionato come un fascino. Era così ovvio una volta che l'hai scritto. Grazie!!
Kilhoffer,

1
Questo funzionerà se hai poche colonne. Se hai diciamo 20 o 30 colonne, puoi comunque usare questo metodo, ma sarebbe scoraggiante. Inoltre, ogni volta che aggiungi una colonna e desideri copiare anche quei dati, devi aggiungere la colonna a questo script. La cosa migliore è generare inserti dinamicamente utilizzando le tabelle sys.
Jeyara

93

Ok, so che è un vecchio problema ma inserisco comunque la mia risposta.

Mi piace questa soluzione. Devo solo specificare le colonne di identità.

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;

La colonna "id" è la colonna Identity e questa è l'unica colonna che devo specificare. È comunque meglio del contrario. :-)

Uso SQL Server. Potresti voler usare " CREATE TABLE" e " UPDATE TABLE" alle righe 1 e 2. Hmm, ho visto che non ho dato davvero la risposta che voleva. Voleva anche copiare l'id in un'altra colonna. Ma questa soluzione è utile per creare una copia con un nuovo ID automatico.

Modifico la mia soluzione con le idee di 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;

È possibile eliminare più di una colonna separandole con un ",". Il: id dovrebbe essere sostituito con l'id della riga che vuoi copiare. MyDatabase, MyTable e IndexField dovrebbero essere sostituiti con i tuoi nomi (ovviamente).


1
Questo è complicato, come puoi essere sicuro di copiare l'id corretto nella riga corretta durante INSERT INTO nella riga 3?
Erno

La colonna id è una colonna identità (nella mia tabella) quindi non mi interessa il valore. Voglio solo un nuovo record che abbia gli stessi valori di quello "vecchio".
Jonas

9
Perché TempTable, non sarebbe meglio usare #TempTable, quindi è una vera tabella temporanea?
Jess

3
Lo sto usando nel seguente formato In 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;questo modo so che verrà ripulito al più presto senza ritardi dalla scrittura di un file intermittente su disco.
Tschallacka

3
Potresti anche usare $identityse non volessi codificare il nome della tua colonna di identità
Factor Mystic,

12

Immagino che tu stia cercando di evitare di scrivere tutti i nomi delle colonne. Se stai utilizzando SQL Management Studio, puoi facilmente fare clic con il pulsante destro del mouse sulla tabella e Script As Insert ... quindi puoi scherzare con quell'output per creare la tua query.


10

Specificare tutti i campi tranne il campo ID.

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

6

Ho lo stesso problema in cui desidero che un singolo script funzioni con una tabella che ha colonne aggiunte periodicamente da altri sviluppatori. Non solo, ma sto supportando molte versioni differenti del nostro database poiché i clienti potrebbero non essere tutti aggiornati con la versione corrente.

Ho preso la soluzione da Jonas e l'ho modificata leggermente. Ciò mi consente di creare una copia della riga e quindi modificare la chiave primaria prima di aggiungerla nuovamente nella tabella di origine originale. Questo è anche molto utile per lavorare con tabelle che non consentono valori NULL nelle colonne e non si desidera dover specificare ogni nome di colonna nell'INSERT.

Questo codice copia la riga per "ABC" in "XYZ"

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

Una volta terminato il rilascio della tabella temp.

DROP TABLE #TempRow;

4

So che la mia risposta è in ritardo per la festa. Ma il modo in cui ho risolto è leggermente diverso da tutte le risposte.

Ho avuto una situazione, ho bisogno di clonare una riga in una tabella tranne poche colonne. Quei pochi avranno nuovi valori. Questo processo dovrebbe supportare automaticamente le modifiche future alla tabella. Ciò implica, clonare il record senza specificare alcun nome di colonna.

Il mio approccio è

  1. Interrogare Sys.Columns per ottenere l'elenco completo delle colonne per la tabella e includere i nomi delle colonne da saltare nella clausola where.
  2. Convertilo in CSV come nomi di colonne.
  3. Build Select ... Inserisci nello script in base a questo.


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)


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

1

Se "chiave" è il tuo campo PK ed è automatico.

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

genererà un nuovo record, copiando field1 e field2 dal record originale


1

La mia tabella ha 100 campi e avevo bisogno di una query per funzionare. Ora posso cambiare qualsiasi numero di campi con una logica condizionale di base e non preoccuparmi della sua posizione ordinale.

  1. Sostituisci il nome della tabella sottostante con il nome della tua tabella

    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. Sostituisci il nome del campo identità originale con il nome del campo PK

    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. Sostituire nuovamente i nomi delle tabelle (sia il nome della tabella di destinazione che il nome della tabella di origine); modifica le tue wherecondizioni

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

0

Puoi fare così:

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

Lì invece di 112 dovresti inserire un numero dell'id massimo nella tabella DENI / FRIEN01P.


0

Ecco come l'ho fatto usando ASP classico e non riuscivo a farlo funzionare con le risposte sopra e volevo essere in grado di copiare un prodotto nel nostro sistema su un nuovo product_id e avevo bisogno che funzionasse anche quando noi aggiungere più colonne alla tabella.

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")

Non penso che sia necessario emettere 5 comandi SQL separati per completarlo. Inoltre, chi determini nel 2 ° comando, che l'ID del prodotto dovrebbe essere 34567?
Jeyara

34567 è solo un esempio. Puoi impostarlo su una variabile o su quello che vuoi. Se hai un modo migliore per farlo in ASP Classic, fammelo sapere. :)
Daniel Nordh

potresti scrivere un proc memorizzato per eseguire tutti questi in una sola riga. Inoltre, di solito PK era un valore di incremento automatico. Quindi assegnare a te stesso non è una buona idea.
Jeyara

Come scriveresti questa procedura? Per favore, illuminami. PK? Se intendi ID articolo, nel nostro sistema utilizziamo gli ID articolo in base al negozio in cui li vendiamo. Ad esempio, il nostro negozio di giocattoli ha tutti un numero di articolo che inizia con 30 e il nostro negozio di articoli sportivi inizia con 60. Inoltre risparmiamo spazio in modo che se lo facciamo ottenere un nuovo colore, ad esempio, possiamo avere un ID articolo accanto agli altri dello stesso tipo. Come detto, questa era la mia soluzione che funziona nel nostro sistema. Il modo in cui imposti le variabili non è così importante e la maggior parte dei programmatori capirebbe cosa funziona per loro e per il loro sistema.
Daniel Nordh

PK sta per chiave primaria. Nel tuo caso è "12345". Vedi stackoverflow.com/questions/21561657/… per come utilizzare stored proc in Classic ASP se non sai come farlo. Per fare ciò, sposta tutti quelli in un proc memorizzato e passa il tuo "12345" come parametro. Il modo in cui funziona funzionerebbe, ma oggigiorno gli script parametrizzati sono quelli consigliati.
Jeyara
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.