Jak skopiować rekord w tabeli SQL, ale zamienić unikatowy identyfikator nowego wiersza?

123

To pytanie jest blisko tego, czego potrzebuję, ale mój scenariusz jest nieco inny. Tabela źródłowa i tabela docelowa są takie same, a klucz podstawowy to unikalny identyfikator (identyfikator guid). Kiedy próbuję tego:

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

Oczywiście dostaję naruszenie ograniczenia klucza podstawowego, ponieważ próbuję skopiować klucz podstawowy. Właściwie nie chcę w ogóle kopiować klucza podstawowego. Raczej chcę stworzyć nowy. Dodatkowo chciałbym selektywnie kopiować niektóre pola, a pozostałe pozostawić puste. Aby sprawy były bardziej skomplikowane, muszę wziąć klucz podstawowy oryginalnego rekordu i wstawić go do innego pola w kopii (pole PreviousId).

Jestem pewien, że istnieje proste rozwiązanie tego problemu, po prostu nie znam wystarczającej liczby TSQL, aby wiedzieć, co to jest.

Kilhoffer
źródło

Odpowiedzi:

186

Spróbuj tego:


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

Wszystkie pola, które nie zostały określone, powinny otrzymać wartość domyślną (która zwykle wynosi NULL, gdy nie są zdefiniowane).

AaronSieb
źródło
2
Niesamowite. Działał jak urok. To było takie oczywiste, kiedy to napisałeś. Dzięki!!
Kilhoffer,
1
To zadziała, jeśli masz kilka kolumn. Jeśli masz powiedzmy 20 lub 30 kolumn, nadal możesz użyć tej metody, ale byłoby to zniechęcające. Ponadto za każdym razem, gdy dodajesz kolumnę i chcesz skopiować również te dane, musisz dodać kolumnę do tego skryptu. Najlepiej jest generować insert dynamicznie przy użyciu tabel sys.
Jeyara
93

Ok, wiem, że to stary problem, ale i tak publikuję odpowiedź.

Podoba mi się to rozwiązanie. Muszę tylko określić kolumny tożsamości.

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;

Kolumna „id” to kolumna tożsamości i jest to jedyna kolumna, którą muszę określić. I tak jest lepiej niż na odwrót. :-)

Używam SQL Server. Możesz użyć „ CREATE TABLE” i „ UPDATE TABLE” w wierszach 1 i 2. Hmm, widziałem, że tak naprawdę nie udzieliłem odpowiedzi, której chciał. Chciał również skopiować identyfikator do innej kolumny. Ale to rozwiązanie jest dobre do tworzenia kopii z nowym automatycznym identyfikatorem.

Edytuję swoje rozwiązanie, korzystając z pomysłów Michaela Dibbetsa.

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;

Możesz usunąć więcej niż jedną kolumnę, oddzielając je znakiem „,”. Pole: id należy zastąpić identyfikatorem wiersza, który chcesz skopiować. MyDatabase, MyTable i IndexField należy zastąpić swoimi nazwami (oczywiście).

Jonas
źródło
1
To trudne, jak możesz być pewien, że kopiujesz poprawny identyfikator do właściwego wiersza podczas INSERT INTO w wierszu 3?
Erno,
Kolumna id jest kolumną tożsamości (w mojej tabeli), więc nie obchodzi mnie wartość. Chcę tylko, aby nowy rekord miał te same wartości, co „stary”.
Jonas
9
Bo TempTableczy nie byłoby lepiej w użyciu #TempTable, więc jest to prawdziwa tabela tymczasowa?
Jess
3
Używam tego w następującym formacie. 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;Dzięki temu wiem, że zostanie wyczyszczone jak najszybciej, bez żadnych opóźnień związanych z zapisaniem sporadycznego pliku na dysk.
Tschallacka
3
Możesz również użyć, $identityjeśli nie chcesz na stałe zakodować nazwy swojej kolumny tożsamości
Factor Mystic
12

Domyślam się, że próbujesz uniknąć zapisywania wszystkich nazw kolumn. Jeśli używasz SQL Management Studio, możesz łatwo kliknąć prawym przyciskiem myszy tabelę i skrypt jako wstaw, a następnie możesz pomieszać się z tymi danymi wyjściowymi, aby utworzyć zapytanie.

Matt Hinze
źródło
10

Określ wszystkie pola oprócz pola ID.

INSERT INTO MyTable (FIELD2, FIELD3, ..., FIELD529, PreviousId)
SELECT FIELD2, NULL, ..., FIELD529, FIELD1
FROM MyTable
WHERE FIELD1 = @Id;
Scott Bevington
źródło
6

Mam ten sam problem, w którym chcę, aby pojedynczy skrypt działał z tabelą, która ma kolumny dodawane okresowo przez innych programistów. Nie tylko to, ale obsługuję wiele różnych wersji naszej bazy danych, ponieważ klienci mogą nie być na bieżąco z aktualną wersją.

Wziąłem rozwiązanie Jonasa i nieznacznie je zmodyfikowałem. Dzięki temu mogę wykonać kopię wiersza, a następnie zmienić klucz podstawowy przed dodaniem go z powrotem do oryginalnej tabeli źródłowej. Jest to również bardzo przydatne do pracy z tabelami, które nie zezwalają na wartości NULL w kolumnach i nie chcesz określać nazwy każdej kolumny w INSERT.

Ten kod kopiuje wiersz „ABC” do „XYZ”

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

Po zakończeniu upuszczania tabeli tymczasowej.

DROP TABLE #TempRow;
TonyT
źródło
4

Wiem, że moja odpowiedź jest spóźniona na przyjęcie. Ale sposób, w jaki rozwiązałem, jest nieco inny niż wszystkie odpowiedzi.

Miałem sytuację, w której muszę sklonować wiersz w tabeli oprócz kilku kolumn. Tych kilku będzie miało nowe wartości. Ten proces powinien automatycznie obsługiwać przyszłe zmiany w tabeli. Oznacza to, że należy sklonować rekord bez określania nazw kolumn.

Moje podejście jest takie,

  1. Zapytaj Sys.Columns, aby uzyskać pełną listę kolumn tabeli i dołączyć nazwy kolumn do pominięcia klauzuli where.
  2. Przekonwertuj to na CSV jako nazwy kolumn.
  3. Kompiluj Wybierz ... Wstaw do skryptu na podstawie tego.


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
źródło
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
źródło
1

Jeśli "klucz" jest twoim polem PK i jest autonumeryczne.

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

wygeneruje nowy rekord, kopiując pole 1 i pole 2 z oryginalnego rekordu

Eduardo Campañó
źródło
1

Moja tabela ma 100 pól i potrzebowałem zapytania, aby po prostu działało. Teraz mogę przełączać dowolną liczbę pól za pomocą podstawowej logiki warunkowej i nie martwić się o ich pozycję porządkową.

  1. Zastąp poniższą nazwę tabeli nazwą swojej tabeli

    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. Zastąp oryginalną nazwę pola tożsamości nazwą pola 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. Zastąp ponownie nazwy tabel (zarówno nazwa tabeli docelowej, jak i nazwa tabeli źródłowej); edytuj swoje wherewarunki

    SQL = "INSERT INTO TARGET-TABLE-NAME (" & columnListTARGET & ") SELECT " & columnListSOURCE & " FROM SOURCE-TABLE-NAME WHERE (FIELDNAME = FIELDVALUE)" 
    Conn.Execute(SQL)
Rit Man
źródło
0

Możesz zrobić tak:

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

Tam zamiast 112 należy wpisać numer maksymalnego identyfikatora w tabeli DENI / FRIEN01P.

Denis Kutlubaev
źródło
0

Oto jak to zrobiłem używając klasycznego ASP i nie mogłem go zmusić do pracy z powyższymi odpowiedziami i chciałem móc skopiować produkt w naszym systemie do nowego product_id i potrzebowałem go, aby mógł działać nawet wtedy, gdy dodaj więcej kolumn do tabeli.

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
źródło
Nie sądzę, abyś musiał wydawać 5 oddzielnych poleceń SQL, aby to zakończyć. A także, kogo określisz w 2. poleceniu, że identyfikator produktu powinien być 34567?
Jeyara
34567 to tylko przykład. Możesz ustawić to na zmienną lub cokolwiek chcesz. Jeśli masz lepszy sposób na zrobienie tego w ASP Classic, daj mi znać. :)
Daniel Nordh
możesz napisać przechowywany proc, aby uruchomić to wszystko w jednej linii. Ponadto, zwykle PK była wartością automatycznego zwiększania. Dlatego przypisywanie do siebie nie jest dobrym pomysłem.
Jeyara
Jak napisałbyś tę procedurę? Proszę, oświeć mnie. PK? Jeśli masz na myśli identyfikatory artykułów, w naszym systemie używamy identyfikatorów artykułów na podstawie tego, w którym sklepie je sprzedajemy. Na przykład wszystkie nasze sklepy z zabawkami mają numery artykułów zaczynające się od 30, a nasz sklep sportowy zaczyna się od 60. Ponadto oszczędzamy miejsce, aby uzyskać nowy kolor, na przykład możemy mieć identyfikator artykułu obok innych tego samego rodzaju. Jak powiedziałem, to było moje rozwiązanie, które działa w naszym systemie. Sposób ustawiania zmiennych nie jest tak ważny i większość programistów zrozumiałaby, co działa dla nich i ich systemu.
Daniel Nordh
PK oznacza klucz podstawowy. W twoim przypadku jest to „12345”. Zobacz stackoverflow.com/questions/21561657/ ... aby dowiedzieć się, jak używać przechowywanych procesów w klasycznej ASP, jeśli nie wiesz, jak to zrobić. Aby to zrobić, przenieś je wszystkie do jednego przechowywanego procesu i przekaż swój parametr „12345”. Sposób, w jaki to robisz, byś działał, ale obecnie zalecane są sparametryzowane skrypty.
Jeyara