SELECT INTO ile bir tabloyu nasıl kopyalarım ama IDENTITY özelliğini yok sayarım?


41

Kimlik sütunu olan bir tablom var diyor ki:

create table with_id (
 id int identity(1,1),
 val varchar(30)
);

Bu iyi bilinmektedir, bu

select * into copy_from_with_id_1 from with_id;

copy_from_with_id_1 ile kimlik numarası da aynı şekilde sonuçlanır.

Aşağıdaki yığın taşması sorusu , tüm sütunların açıkça listelenmesinden bahseder.

Hadi deneyelim

select id, val into copy_from_with_id_2 from with_id;

Hata! Bu durumda bile id bir kimlik sütunu.

İstediğim şey masa gibi

create table without_id (
 id int,
 val varchar(30)
);

Yanıtlar:


52

Gönderen Books Online

New_table'ın biçimi, seçim listesindeki ifadeleri değerlendirerek belirlenir. New_table'daki sütunlar, seçim listesi tarafından belirtilen sırada oluşturulur. New_table'daki her sütun, seçim listesindeki karşılık gelen ifadeyle aynı ada, veri türüne, boşuna ve değere sahiptir. Bir sütunun KİMLİK özelliği , Açıklamalar bölümünde "Kimlik Sütunları ile Çalışma" bölümünde belirtilen koşullar dışında aktarılır .

Sayfa aşağı:

Mevcut bir kimlik sütunu yeni bir tabloya seçildiğinde, yeni sütun, aşağıdaki koşullardan biri doğru olmadıkça, IDENTITY özelliğini miras alır:

  • SELECT ifadesi, join, GROUP BY yantümcesi veya toplama işlevini içerir.
  • UNION kullanılarak çoklu SELECT ifadeleri birleştirilir.
  • Kimlik sütunu, seçim listesinde birden fazla kez listelenir.
  • Kimlik sütunu bir ifadenin parçasıdır.
  • Kimlik sütunu uzak bir veri kaynağındandır.

Bu koşullardan herhangi biri doğruysa, IDENTITY özelliğini miras almak yerine sütun NOT NULL oluşturulur. Yeni tabloda bir kimlik sütunu gerekli, ancak böyle bir sütun mevcut değilse veya kaynak kimliği sütunundan farklı bir tohum veya artış değeri istiyorsanız, IDENTITY işlevini kullanarak seçim listesindeki sütunu tanımlayın. Aşağıdaki Örnekler bölümündeki "KİMLİK işlevini kullanarak bir kimlik sütunu oluşturma" konusuna bakın.

Yani ... teorik olarak kaçabilirsiniz:

select id, val 
into copy_from_with_id_2 
from with_id

union all

select 0, 'test_row' 
where 1 = 0;

Bunu açıklamak için bu kodu yorumlamak önemlidir, bir dahaki sefere bakıldığında kaldırılsın diye.


29

Erics'in cevabından ilham alan, yalnızca tablo adlarına bağlı olan ve belirli bir sütun adı kullanmayan aşağıdaki çözümü buldum:

select * into without_id from with_id where 1 = 0
union all
select * from with_id where 1 = 0
;
insert into without_id select * from with_id;

Düzenle

Bunu geliştirmek bile mümkündür

select * into without_id from with_id
union all
select * from with_id where 1 = 0
;

13

Yeni tabloyu bir seferde oluşturmak ve doldurmak için bir birleştirme kullanabilirsiniz:

SELECT
  t.*
INTO
  dbo.NewTable
FROM
  dbo.TableWithIdentity AS t
  LEFT JOIN dbo.TableWithIdentity ON 1 = 0
;

1 = 0Durum nedeniyle , sağ taraf eşleşmeyecek ve böylece sol yan sıraların tekrarlanmasını önleyecektir ve bu bir dış bağlantı olduğundan, sol sıra sıraları da ortadan kaldırılmayacaktır. Son olarak, bu bir birleşim olduğu için, KİMLİK özelliği ortadan kaldırılmıştır.

Bu nedenle, yalnızca soldaki sütunların seçilmesi, yalnızca veri şeklinde, yani IDENTITY özelliğinin çıkarılmasıyla , dbo.TableWithIdentity'nin tam bir kopyasını üretecektir .

Tüm söylenenler, Max Vernon , akılda tutmaya değer bir yorumda geçerli bir noktaya değindi. Yukarıdaki sorgunun yürütme planına bakarsanız:

Yürütme planı

kaynak tablonun yürütme planında sadece bir kez belirtildiğini fark edeceksiniz. Diğer örnek, optimiser tarafından elimine edildi.

Bu nedenle, eğer optimizatör planın birleşme noktasının sağ tarafının plana gerek duymadığını doğru bir şekilde tespit edebiliyorsa, SQL Server'ın gelecekteki bir sürümünde, IDENTITY özelliğinin gerekmediğine karar verebileceğini beklemek makul olmalıdır. Sorgu planına göre ayarlanan kaynak satırında artık başka bir KİMLİK sütunu olmadığından, ikisi de kaldırıldı. Bu, yukarıdaki sorgunun bir noktada beklendiği gibi çalışmayı durdurabileceği anlamına gelir.

Doğru tarafından belirtildiği gibi, ypercubeᵀᴹ , bugüne kadar manuel açıkça katılmak varsa, KİMLİK özelliği korunmuş olmadığını belirten olmuştur:

Varolan bir kimlik sütunu yeni bir tabloya seçildiğinde, yeni sütun, [...] [t] SELECT ifadesinde bir birleşim içermedikçe, IDENTITY özelliğini devralır.

Bu yüzden, kılavuz söz etmeye devam ettiği sürece, davranışların aynı kalacağından emin olabiliriz.

Şeref Shaneis ve ypercubeᵀᴹ sohbet ilgili konusunu gündeme getirmek için.


Misiniz JOIN (SELECT 1) AS dummy ON 1 = 1da işe?
ypercubeᵀᴹ


5

Bu kodu dene ..

SELECT isnull(Tablename_old.IDENTITYCOL + 0, -1) AS 'New Identity Column'
INTO   dbo.TableName_new
FROM   dbo.TableName_old 

ISNULLÇağrı yeni sütun ile oluşturulan olmasını sağlar NOT NULLnullability.


1
Öyle mi ISNULL()yoksa +0bunu yapar mı? Ya da her ikisi de gerekli?
ypercubeᵀᴹ

3

Sadece farklı bir yol göstermek için:

Bağlantılı bir sunucu kullanabilirsiniz .

SELECT * 
INTO without_id 
FROM [linked_server].[source_db].dbo.[with_id];

Bunu kullanarak geçici olarak yerel sunucuya bağlı bir sunucu oluşturabilirsiniz:

DECLARE @LocalServer SYSNAME 
SET @LocalServer = @@SERVERNAME;
EXEC master.dbo.sp_addlinkedserver @server = N'localserver'
    , @srvproduct = ''
    , @provider = 'SQLNCLI'
    , @datasrc = @LocalServer;
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'localserver'
    , @useself = N'True'
    , @locallogin = NULL
    , @rmtuser = NULL
    , @rmtpassword = NULL;

Hangi noktada, select * intokodu çalıştırarak localserverbağlı sunucuya dört bölümlü adı atıfta bulunuyorsunuz :

SELECT * 
INTO without_id 
FROM [localserver].[source_db].dbo.[with_id];

Bu işlem tamamlandıktan sonra, localserverbağlantılı sunucuyu şununla temizleyin :

EXEC sp_dropserver @server = 'localserver'
    , @droplogins = 'droplogins';

Veya OPENQUERYsözdizimini kullanabilirsiniz

SELECT * 
INTO without_id 
FROM OPENQUERY([linked_server], 'SELECT * FROM [source_db].dbo.[with_id]');

1

Select deyimi bir birleşim içeriyorsa identity özelliği aktarılmaz.

select a.* into without_id from with_id a inner join with_id b on 1 = 0;

aynı zamanda istenen davranışı (kopyalanan idsütunun IDENTITYözelliği saklamaması için de verir . Ancak, herhangi bir satırın kopyalanmaması gibi bir yan etkisi olacaktır. (bazı diğer yöntemlerde olduğu gibi)

insert into without_id select * from with_id;

(teşekkürler AakashM!)


1

Kolay yolu, sütunu bir ifadenin parçası yapmaktır.

Örnek:
Eğer dbo.Employee tablosu ID sütununda bir kimliğe sahipse, aşağıdaki örnekteki temp table #t'de ID sütununda bir IDENTITY olacaktır.

--temp table has IDENTITY
select ID, Name 
into #t
from dbo.Employee

ID'ye bir ifade uygulamak için bunu değiştirin ve #t artık ID sütununda bir IDENTITY sahibi olmayacak. Bu durumda, ID sütununa basit bir eklenti uygularız.

--no IDENTITY
select ID = ID + 0, Name 
into #t
from dbo.Employee

Diğer veri türleri için diğer ifade örnekleri şunları içerebilir: convert (), string bitiştirme veya Isnull ()


1
Gönderen docs.microsoft.com/en-us/sql/t-sql/queries/... : Aşağıdaki koşullardan biri doğru değilse “Varolan kimlik sütunu yeni tabloya seçildiğinde, yeni sütun, KİMLİK özelliğini miras … Kimlik sütunu ifadenin bir parçası… Sütun, IDENTITY özelliğini devralmak yerine NULL DEĞİLDİR. ”
Manngo

1

Bazen, sütunun KİMLİK kullanılarak oluşturulup oluşturulmadığını bilmediğiniz (veya umursamadığınız) bir tablodan eklemek istersiniz. Üzerinde çalıştığınız bir tamsayı sütun bile olmayabilir. Bu durumda, aşağıdakiler işe yarayacaktır:

SELECT TOP(0) ISNULL([col],NULL) AS [col], ... INTO [table2] FROM [table1]
ALTER TABLE [table2] REBUILD WITH (DATA_COMPRESSION=page)
INSERT INTO [table2] ...

ISNULL, IDENTITY niteliğini sütundan çıkarır, ancak aynı sütuna yazar ve asıl sütuna yazar ve aynı zamanda geçersiz hale getirmez. TOP (0), seçili satırları eklemek için kullanabileceğiniz boş bir tablo oluşturur. Gerekirse, verileri eklemeden önce tabloyu sıkıştırılmış hale getirebilirsiniz.


0
select convert(int, id) as id, val 
into copy_from_with_id_without_id 
from with_id;

kimliği kaldıracak.

Dezavantajı bu idnull olur olur ama bu kısıtlamayı ekleyebilirsiniz.


1
Sen hiç ISNULL kullanabilirsiniz etrafında almak söyledi.
Erik Darling,

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.