Bagaimana cara mengubah nilai kolom identitas secara terprogram?

160

Saya memiliki database MS SQL 2005 dengan tabel Testdengan kolom ID. IDadalah kolom identitas.

Saya memiliki baris dalam tabel ini dan semuanya memiliki nilai ID otomatis yang sesuai.

Sekarang saya ingin mengubah setiap ID dalam tabel ini seperti ini:

ID = ID + 1

Tetapi ketika saya melakukan ini saya mendapatkan kesalahan:

Tidak dapat memperbarui 'ID' kolom identitas.

Saya sudah mencoba ini:

    ALTER TABLE Test NOCHECK CONSTRAINT ALL 
    set identity_insert ID ON

Tapi ini tidak menyelesaikan masalah.

Saya perlu menetapkan identitas pada kolom ini, tetapi saya perlu mengubah nilai juga dari waktu ke waktu. Jadi pertanyaan saya adalah bagaimana menyelesaikan tugas ini.

Tomasz Smykowski
sumber

Jawaban:

220

Kamu butuh

set identity_insert YourTable ON

Kemudian hapus baris Anda dan masukkan kembali dengan identitas yang berbeda.

Setelah Anda selesai memasukkan, jangan lupa mematikan identitas_insert

set identity_insert YourTable OFF
AK
sumber
133
pengaturan ini hanya akan berfungsi saat memasukkan data dan tidak saat memperbarui. Pernyataan UPDATE masih akan gagal.
Husein Roncevic
31
Untuk pembaruan, Anda perlu menghapus dan memasukkan kembali. Tidak ada jalan lain.
ashes999
1
@MartinSmith solusi Anda sepertinya terlalu panjang. Mampu melakukannya dalam dua langkah (identitas-off, hapus / sisipkan, identitas-on) jauh lebih efektif.
ashes999
3
@ ashes999 Itu adalah 4 langkah bukan 2. Jawaban saya hanya satu lagi (buat tabel, beralih, perbarui, beralih kembali, jatuhkan) Mungkin Anda lebih terbiasa dengan langkah-langkah ini sehingga terlihat kurang berbelit-belit. Memperbarui bisa jauh lebih efisien daripada menghapus sisipan ketika banyak baris terlibat. Di mana Anda memegang baris yang dihapus? Jika #temptabel yang Anda letakkan itu adalah langkah lain yang belum Anda hitung di sini.
Martin Smith
40

IDENTITY nilai kolom tidak dapat diubah.

Namun dimungkinkan untuk mengganti metadata tabel untuk menghapus IDENTITYproperti, melakukan pembaruan, lalu beralih kembali.

Dengan asumsi struktur berikut

CREATE TABLE Test
(
ID INT IDENTITY(1,1) PRIMARY KEY,
X VARCHAR(10)
)

INSERT INTO Test 
OUTPUT INSERTED.*
SELECT 'Foo' UNION ALL
SELECT 'Bar' UNION ALL
SELECT 'Baz'

Maka Anda bisa melakukannya

/*Define table with same structure but no IDENTITY*/
CREATE TABLE Temp
(
ID INT PRIMARY KEY,
X VARCHAR(10)
)

/*Switch table metadata to new structure*/
ALTER TABLE Test SWITCH TO Temp;

/*Do the update*/
UPDATE Temp SET ID = ID + 1;

/*Switch table metadata back*/
ALTER TABLE Temp SWITCH TO Test;

/*ID values have been updated*/
SELECT *
FROM Test

/*Safety check in case error in preceding step*/
IF NOT EXISTS(SELECT * FROM Temp)
    DROP TABLE Temp /*Drop obsolete table*/

Dalam SQL Server 2012 dimungkinkan untuk memiliki kolom penambahan otomatis yang juga dapat diperbarui dengan lebih mudah SEQUENCES

CREATE SEQUENCE Seq
    AS INT
    START WITH 1
    INCREMENT BY 1

CREATE TABLE Test2
(
ID INT DEFAULT NEXT VALUE FOR Seq NOT NULL PRIMARY KEY,
X VARCHAR(10)
)

INSERT INTO Test2(X)
SELECT 'Foo' UNION ALL
SELECT 'Bar' UNION ALL
SELECT 'Baz'

UPDATE Test2 SET ID+=1
Martin Smith
sumber
1
Sangat licin. Pelajari sesuatu yang baru setiap hari (BTW saya menguji ini di SQLExpress; meskipun SWITCH TO tidak menggunakan partisi, tampaknya). Perhatikan bahwa tabel harus persis sama persis (indeks, FK, dll)
Mark Sowul
1
Apakah metode sakelar berfungsi saat Anda memiliki PK, FK, Indeks, dan Tampilan yang dibangun di atas tabel asli? Apakah mereka akan putus dengan menggunakan metode ini?
tj
1
@ tj saat membuat skrip temp table dari tabel sumber termasuk semua indeks dan batasan. Kemudian, ubah nama tabel dan batasan untuk menghindari tabrakan. Tampilan tidak akan menyebabkan masalah kecuali diindeks atau skemabound.
Martin Smith
Tidak berfungsi jika ada indeks pencarian teks lengkap di atas meja. Saya kira itu mungkin untuk menghapusnya dan membuatnya kembali setelah itu, tetapi saya belum mengujinya.
youen
26

Melalui UI di SQL Server 2005 manager, ubah kolom hapus properti autonumber (identitas) dari kolom (pilih tabel dengan mengklik kanan padanya dan pilih "Desain").

Kemudian jalankan kueri Anda:

UPDATE table SET Id = Id + 1

Lalu pergi dan tambahkan properti autonumber kembali ke kolom.

Michael Pryor
sumber
3
Jika Anda membuat perubahan secara manual, Anda dapat meminta manajer untuk membuat skrip SQL untuk perubahan (menu desainer tabel, buat skrip perubahan). Untuk perubahan ini, ia membuat tabel baru dan menyalin data, lalu menghapus yang asli.
Robin Bennett
2
@tomaszs - Sebuah contoh kode yang juga lebih efisien karena tidak secara fisik membangun kembali tabel sama sekali (ini akan melakukannya dua kali) ada di jawaban saya di sini
Martin Smith
Anda tidak dapat menambahkan identitas kembali. Apakah kamu? stackoverflow.com/questions/1049210/...
Tomas Kubes
Terima kasih. Ini sempurna. Saya memiliki 1 baris di meja saya yang tidak saya sadari, jadi skrip bootstrap saya untuk meja saya memiliki Idnilai Identitas Otomatis dimatikan oleh 1.
Shiva
18

Pertama-tama pengaturan IDENTITY_INSERT aktif atau nonaktif dalam hal ini tidak akan berfungsi untuk apa yang Anda butuhkan (digunakan untuk memasukkan nilai baru, seperti memasukkan celah).

Melakukan operasi melalui GUI hanya membuat tabel sementara, menyalin semua data ke tabel baru tanpa bidang identitas, dan mengganti nama tabel.

Miles D
sumber
9

Ini bisa dilakukan dengan menggunakan tabel sementara.

Ide

  • nonaktifkan kendala (jika id Anda dirujuk oleh kunci asing)
  • buat tabel temp dengan id baru
  • hapus konten tabel
  • salin kembali data dari tabel yang disalin ke tabel asli Anda
  • aktifkan pembatasan yang dinonaktifkan sebelumnya

Pertanyaan SQL

Katakanlah testtabel Anda memiliki dua kolom tambahan ( column2dan column3) dan ada 2 tabel yang memiliki referensi kunci asing testdipanggil foreign_table1dan foreign_table2(karena masalah kehidupan nyata tidak pernah sederhana).

alter table test nocheck constraint all;
alter table foreign_table1 nocheck constraint all;
alter table foreign_table2 nocheck constraint all;
set identity_insert test on;

select id + 1 as id, column2, column3 into test_copy from test v;
delete from test;
insert into test(id, column2, column3)
select id, column2, column3 from test_copy

alter table test check constraint all;
alter table foreign_table1 check constraint all;
alter table foreign_table2 check constraint all;
set identity_insert test off;
drop table test_copy;

Itu dia.

Manitra Andriamitondra
sumber
6

DBCC CHECKIDENT ('databasename.dbo.orders', RESEED, 999) Anda dapat mengubah nomor kolom identitas apa pun dengan perintah ini, dan Anda juga dapat memulai nomor bidang itu dari setiap nomor yang Anda inginkan. Misalnya dalam perintah saya saya minta mulai dari 1000 (999 +1) berharap itu akan cukup ... semoga berhasil

Roxana
sumber
4

Jika kolom bukan PK Anda selalu bisa membuat kolom BARU di tabel dengan angka yang bertambah, jatuhkan yang asli dan kemudian ubah yang baru menjadi yang lama.

ingin tahu mengapa Anda mungkin perlu melakukan ini ... paling saya pernah harus futz dengan kolom Identity adalah untuk mengisi ulang angka dan saya akhirnya menggunakan DBCC CHECKIDENT (nama tab, nama, RESEED, newnextnumber)

semoga berhasil!

Christopher Klein
sumber
1

Memodifikasi identitas mungkin gagal tergantung pada sejumlah faktor, terutama berputar di sekitar objek / hubungan yang terhubung ke kolom id. Sepertinya desain db adalah sebagai masalah di sini karena id harus jarang jika pernah berubah (saya yakin Anda punya alasan dan cascasding perubahan). Jika Anda benar-benar perlu mengubah id dari waktu ke waktu, saya sarankan untuk membuat kolom id dummy baru yang bukan kunci utama / nomor otomatis yang dapat Anda kelola sendiri dan hasilkan dari nilai saat ini. Bergantian, ide Chrisotphers di atas akan menjadi saran saya yang lain jika Anda mengalami masalah dengan mengizinkan penyisipan identitas.

Semoga berhasil

PS itu tidak gagal karena urutan berurutan yang sedang berjalan berusaha memperbarui nilai dalam daftar ke item yang sudah ada dalam daftar id? mencengkeram sedotan, mungkin menambahkan jumlah baris + 1, maka jika itu berhasil kurangi jumlah baris: -S

Penyamak
sumber
1

Jika Anda perlu mengubah ID sesekali, mungkin sebaiknya tidak menggunakan kolom identitas. Di masa lalu kami telah mengimplementasikan bidang nomor otomatis secara manual menggunakan tabel 'Penghitung' yang melacak ID berikutnya untuk setiap tabel. IIRC kami melakukan ini karena kolom identitas menyebabkan kerusakan basis data di SQL2000 tetapi bisa mengubah ID kadang-kadang berguna untuk pengujian.

Robin Bennett
sumber
1

Anda bisa menyisipkan baris baru dengan nilai yang dimodifikasi dan kemudian menghapus baris lama. Contoh berikut mengubah ID agar sama dengan PersonId kunci asing

SET IDENTITY_INSERT [PersonApiLogin] ON

INSERT INTO [PersonApiLogin](
       [Id]
      ,[PersonId]
      ,[ApiId]
      ,[Hash]
      ,[Password]
      ,[SoftwareKey]
      ,[LoggedIn]
      ,[LastAccess])
SELECT [PersonId]
      ,[PersonId]
      ,[ApiId]
      ,[Hash]
      ,[Password]
      ,[SoftwareKey]
      ,[LoggedIn]
      ,[LastAccess]
FROM [db304].[dbo].[PersonApiLogin]
GO

DELETE FROM [PersonApiLogin]
WHERE [PersonId] <> ID
GO
SET IDENTITY_INSERT [PersonApiLogin] OFF
GO
Tomas Kubes
sumber
1

Pertama-tama simpan semua ID dan ubah secara terprogram ke nilai yang tidak Anda inginkan, kemudian hapus dari basis data dan kemudian masukkan lagi menggunakan sesuatu yang serupa:

use [Name.Database]
go
set identity_insert [Test] ON
insert into [dbo].[Test]
           ([Id])
     VALUES
           (2)
set identity_insert [Test] OFF

Untuk penggunaan insert massal:

use [Name.Database]
go
set identity_insert [Test] ON
BULK INSERT [Test]
FROM 'C:\Users\Oscar\file.csv'
WITH (FIELDTERMINATOR = ';',
      ROWTERMINATOR = '\n',
      KEEPIDENTITY)
set identity_insert [Test] OFF

Sampel data dari file.csv:

2;
3;
4;
5;
6;

Jika Anda tidak identity_insertmematikan, Anda akan mendapatkan kesalahan berikut:

Tidak dapat memasukkan nilai eksplisit untuk kolom identitas dalam tabel 'Tes' ketika IDENTITY_INSERT diatur ke OFF.

Ogglas
sumber
0

Saya melihat artikel bagus yang membantu saya keluar pada saat terakhir .. Saya mencoba untuk memasukkan beberapa baris dalam tabel yang memiliki kolom identitas tetapi melakukannya dengan salah dan harus menghapus kembali. Setelah saya menghapus baris maka kolom identitas saya berubah. Saya mencoba menemukan cara untuk memperbarui kolom yang dimasukkan tetapi - tidak berhasil. Jadi, saat mencari di google ditemukan tautan ..

  1. Menghapus kolom yang salah dimasukkan
  2. Gunakan masukkan paksa menggunakan identitas hidup / mati (dijelaskan di bawah)

http://beyondrelational.com/modules/2/blogs/28/posts/10337/sql-server-how-do-i-insert-an-explicit-value-into-an-identity-column-how-do- i-perbarui-nilai-an.aspx

Balu
sumber
1
Namun, tidak yakin Anda telah menjawab pertanyaan di sini.
Andrew Barber
0

Pertanyaan yang sangat bagus, pertama-tama kita perlu di IDENTITY_INSERT untuk tabel tertentu, setelah itu jalankan permintaan memasukkan (Harus menentukan nama kolom).

Catatan: Setelah mengedit kolom identitas, jangan lupa mematikan IDENTITY_INSERT. Jika belum selesai, Anda tidak dapat mengedit kolom identitas untuk tabel lainnya.

SET IDENTITY_INSERT Emp_tb_gb_Menu ON
     INSERT Emp_tb_gb_Menu(MenuID) VALUES (68)
SET IDENTITY_INSERT Emp_tb_gb_Menu OFF

http://allinworld99.blogspot.com/2016/07/how-to-edit-identity-field-in-sql.html

Asith Raj
sumber