Bagaimana Anda menyalin record dalam tabel SQL tetapi menukar id unik dari baris baru?

123

Pertanyaan ini mendekati apa yang saya butuhkan, tetapi skenario saya sedikit berbeda. Tabel sumber dan tabel tujuan sama dan kunci utamanya adalah pengidentifikasi unik (guid). Ketika saya mencoba ini:

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

Saya jelas mendapatkan pelanggaran batasan kunci utama, karena saya mencoba menyalin kunci utama. Sebenarnya, saya sama sekali tidak ingin menyalin kunci utama. Sebaliknya, saya ingin membuat yang baru. Selain itu, saya ingin menyalin bidang tertentu secara selektif, dan membiarkan yang lain kosong. Untuk membuat masalah lebih kompleks, saya perlu mengambil kunci utama dari rekaman asli, dan memasukkannya ke bidang lain di salinan (bidang Id Sebelumnya).

Saya yakin ada solusi mudah untuk ini, saya hanya tidak tahu cukup TSQL untuk mengetahui apa itu.

Kilhoffer
sumber

Jawaban:

186

Coba ini:


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

Setiap bidang yang tidak ditentukan harus menerima nilai defaultnya (yang biasanya NULL jika tidak ditentukan).

AaronSieb
sumber
2
Mengagumkan. Bekerja seperti pesona. Itu sangat jelas setelah Anda menuliskannya. Terima kasih!!
Kilhoffer
1
Ini akan berfungsi jika Anda memiliki sedikit kolom. Jika Anda mengatakan 20 atau 30 kolom, Anda tetap dapat menggunakan metode ini, tetapi itu akan menakutkan. Juga, setiap kali Anda menambahkan kolom dan ingin menyalin data itu juga, perlu menambahkan kolom ke skrip ini. Yang terbaik adalah membuat sisipan secara dinamis menggunakan tabel sys.
Jeyara
93

Oke, saya tahu ini masalah lama, tetapi saya tetap memposting jawaban saya.

Saya suka solusi ini. Saya hanya perlu menentukan kolom identitas.

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;

Kolom "id" adalah kolom identitas dan itulah satu-satunya kolom yang harus saya tentukan. Lagipula itu lebih baik daripada sebaliknya. :-)

Saya menggunakan SQL Server. Anda mungkin ingin menggunakan " CREATE TABLE" dan " UPDATE TABLE" di baris 1 dan 2. Hmm, saya melihat bahwa saya tidak benar-benar memberikan jawaban yang dia inginkan. Dia juga ingin menyalin id ke kolom lain. Tetapi solusi ini bagus untuk membuat salinan dengan auto-id baru.

Saya mengedit solusi saya dengan idéas dari 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;

Anda dapat melepaskan lebih dari satu kolom dengan memisahkannya dengan ",". : Id harus diganti dengan id dari baris yang ingin Anda salin. MyDatabase, MyTable dan IndexField harus diganti dengan nama Anda (tentu saja).

Jonas
sumber
1
Ini rumit, bagaimana Anda bisa yakin bahwa Anda menyalin id yang benar ke baris yang benar selama INSERT INTO di baris 3?
Erno
Id-kolom adalah kolom identitas (di tabel saya) jadi saya tidak peduli dengan nilainya. Saya hanya ingin rekor baru yang memiliki nilai yang sama dengan yang "lama".
Jonas
9
Karena TempTable, bukankah lebih baik digunakan #TempTable, jadi ini adalah tabel sementara yang sebenarnya?
Jess
3
Saya menggunakan ini dalam format berikut. 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;Dengan cara ini saya tahu ini akan segera dibersihkan tanpa penundaan dari menulis file intermittend ke disk.
Tschallacka
3
Anda juga dapat menggunakan $identityjika Anda tidak ingin membuat kode keras nama kolom identitas Anda
Factor Mystic
12

Saya menduga Anda mencoba untuk tidak menuliskan semua nama kolom. Jika Anda menggunakan SQL Management Studio, Anda dapat dengan mudah mengklik kanan pada tabel dan Script As Insert .. maka Anda dapat mengotak-atik output tersebut untuk membuat kueri.

Matt Hinze
sumber
10

Tentukan semua bidang kecuali bidang ID Anda.

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

Saya memiliki masalah yang sama di mana saya ingin satu skrip bekerja dengan tabel yang kolomnya ditambahkan secara berkala oleh pengembang lain. Tidak hanya itu, tetapi saya mendukung berbagai versi database kami karena pelanggan mungkin tidak semuanya up-to-date dengan versi saat ini.

Saya mengambil solusi dari Jonas dan mengubahnya sedikit. Ini memungkinkan saya untuk membuat salinan baris dan kemudian mengubah kunci utama sebelum menambahkannya kembali ke tabel sumber asli. Ini juga sangat berguna untuk bekerja dengan tabel yang tidak mengizinkan nilai NULL dalam kolom dan Anda tidak ingin menentukan setiap nama kolom di INSERT.

Kode ini menyalin baris untuk 'ABC' ke 'XYZ'

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

Setelah Anda menyelesaikan drop tabel temp.

DROP TABLE #TempRow;
TonyT
sumber
4

Saya tahu jawaban saya terlambat ke pesta. Tetapi cara saya memecahkan sedikit berbeda dari semua jawaban.

Saya mengalami situasi, saya perlu mengkloning baris dalam tabel kecuali beberapa kolom. Beberapa orang itu akan memiliki nilai baru. Proses ini akan mendukung secara otomatis untuk perubahan tabel di masa mendatang. Ini berarti, klon record tanpa menentukan nama kolom apa pun.

Pendekatan saya adalah,

  1. Query Sys.Columns untuk mendapatkan daftar lengkap kolom untuk tabel dan menyertakan nama kolom untuk melewati di mana klausa.
  2. Ubah itu menjadi CSV sebagai nama kolom.
  3. Build Select ... Sisipkan ke dalam skrip berdasarkan ini.


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
sumber
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
sumber
1

Jika "kunci" adalah bidang PK Anda dan itu autonumerik.

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

itu akan menghasilkan rekor baru, menyalin field1 dan field2 dari catatan asli

Eduardo Campañó
sumber
1

Tabel saya memiliki 100 bidang, dan saya membutuhkan kueri agar dapat berfungsi. Sekarang saya dapat mengganti sejumlah bidang dengan beberapa logika bersyarat dasar dan tidak khawatir tentang posisi ordinalnya.

  1. Ganti nama tabel di bawah ini dengan nama tabel Anda

    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. Ganti nama bidang identitas asli dengan nama bidang PK Anda

    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. Ganti nama tabel lagi (nama tabel target dan nama tabel sumber); edit wherekondisi Anda

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

Anda bisa melakukan seperti ini:

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

Di sana, alih-alih 112 Anda harus meletakkan sejumlah id maksimum dalam tabel DENI / FRIEN01P.

Denis Kutlubaev
sumber
0

Berikut adalah cara saya melakukannya menggunakan ASP klasik dan tidak bisa membuatnya berfungsi dengan jawaban di atas dan saya ingin dapat menyalin produk di sistem kami ke product_id baru dan membutuhkannya agar dapat berfungsi bahkan ketika kami tambahkan lebih banyak kolom ke tabel.

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
sumber
Saya tidak berpikir Anda perlu mengeluarkan 5 perintah SQL terpisah untuk menyelesaikan ini. Dan juga, siapa yang Anda tentukan di perintah ke-2, id produk itu harus 34567?
Jeyara
34567 hanyalah sebuah contoh. Anda dapat mengaturnya ke variabel atau apapun yang Anda inginkan. Jika Anda memiliki cara yang lebih baik untuk melakukan ini di ASP Classic, beri tahu saya. :)
Daniel Nordh
Anda bisa menulis proc yang disimpan untuk menjalankan semua ini dalam satu baris. Juga, biasanya PK digunakan sebagai nilai kenaikan otomatis. Jadi menugaskan kepada diri sendiri bukanlah ide yang baik.
Jeyara
Bagaimana Anda akan menulis prosedur tersebut? Tolong beri saya pencerahan. PK? Jika yang Anda maksud adalah ID artikel, dalam sistem kami kami menggunakan ID artikel berdasarkan toko tempat kami menjualnya. Misalnya toko mainan kami semua memiliki nomor artikel dimulai dengan 30 dan toko olahraga kami dimulai dengan 60. Ditambah kami menghemat ruang sehingga jika kami mendapatkan warna baru, misalnya, kita dapat memiliki ID artikel di samping yang lain dari jenis yang sama. Seperti yang dikatakan, ini adalah solusi saya yang berfungsi di sistem kami. Bagaimana Anda mengatur variabel tidak begitu penting dan kebanyakan programmer akan memahami apa yang berhasil untuk mereka dan sistem mereka.
Daniel Nordh
PK adalah singkatan dari kunci primer. Dalam kasus Anda, ini adalah '12345'. Lihat stackoverflow.com/questions/21561657/… untuk cara menggunakan proc yang disimpan di ASP Klasik jika Anda tidak tahu caranya. Untuk melakukan ini, pindahkan semua ke dalam satu proc yang tersimpan dan berikan '12345' Anda sebagai parameter. Cara Anda melakukannya akan berhasil tetapi Skrip berparameter direkomendasikan hari ini.
Jeyara