SELECT INTO를 사용하여 테이블을 복사하지만 IDENTITY 속성을 무시하는 방법은 무엇입니까?


41

ID 열이있는 테이블이 있습니다.

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

잘 알려져 있습니다.

select * into copy_from_with_id_1 from with_id;

아이디가 id 인 copy_from_with_id_1이됩니다.

다음 스택 오버플로 질문은 모든 열을 명시 적으로 나열하는 것을 언급합니다.

해보자

select id, val into copy_from_with_id_2 from with_id;

죄송합니다.이 경우에도 id는 ID 열입니다.

내가 원하는 것은 다음과 같은 표입니다.

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

답변:


52

에서 온라인

new_table의 형식은 선택 목록의 표현식을 평가하여 결정됩니다. new_table의 열은 선택 목록에 지정된 순서대로 작성됩니다. new_table의 각 열은 선택 목록의 해당 표현식과 동일한 이름, 데이터 유형, 널 입력 가능 및 값을 갖습니다. 비고 섹션의 "ID 열 작업"에 정의 된 조건을 제외하고 열의 IDENTITY 속성이 전송 됩니다.

페이지 아래로 :

기존 ID 열을 새 테이블로 선택하면 다음 조건 중 하나에 해당하지 않는 한 새 열이 IDENTITY 속성을 상속합니다.

  • SELECT 문에 조인, GROUP BY 절 또는 집계 함수가 있습니다.
  • UNION을 사용하여 여러 SELECT 문을 조인합니다.
  • ID 열이 선택 목록에 두 번 이상 나열되었습니다.
  • ID 열은 표현식의 일부입니다.
  • ID 열은 원격 데이터 소스에서 가져옵니다.

이러한 조건 중 하나에 해당하면 IDENTITY 속성을 상속하는 대신 열이 NOT NULL로 만들어집니다. 새 테이블에 ID 컬럼이 필요하지만 해당 컬럼을 사용할 수 없거나 소스 ID 컬럼과 다른 시드 또는 증분 값을 원하는 경우 IDENTITY 함수를 사용하여 선택 목록에서 컬럼을 정의하십시오. 아래 예 섹션에서 "IDENTITY 함수를 사용하여 ID 열 작성"을 참조하십시오.

그래서 ... 이론적으로 도망 칠 수 있습니다.

select id, val 
into copy_from_with_id_2 
from with_id

union all

select 0, 'test_row' 
where 1 = 0;

다음에 누군가 코드를 볼 때 제거되지 않도록 설명하기 위해이 코드를 주석 처리하는 것이 중요합니다.


29

Erics의 답변에서 영감을 얻은 테이블 이름에만 의존하고 특정 열 이름을 사용하지 않는 다음 솔루션을 찾았습니다.

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;

편집하다

이것을 향상시키는 것도 가능합니다.

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

13

조인을 사용하여 한 번에 새 테이블을 작성하고 채울 수 있습니다.

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

왜냐하면의 1 = 0상태, 오른쪽에는 경기가없고, 따라서 좌측 행의 중복을 방지하고,이 외부 조인하기 때문에, 좌측 열은 어느 제거되지 것이다. 마지막으로 이것이 조인이므로 IDENTITY 속성이 제거됩니다.

따라서 왼쪽 열만 선택하면 데이터 방식으로 만 dbo.TableWithIdentity 의 정확한 사본이 생성 됩니다. 즉, IDENTITY 속성이 제거됩니다.

말했다되는 것을 모두, 최대 버논 염두에 가치가 유지 코멘트에 유효한 점을 올렸다. 위 쿼리의 실행 계획을 보면 :

실행 계획

소스 테이블이 실행 계획에서 한 번만 언급 된 것을 알 수 있습니다. 다른 인스턴스는 옵티 마이저에 의해 제거되었습니다.

따라서 옵티마이 저가 계획에서 조인의 오른쪽이 필요하지 않다고 올바르게 설정할 수 있다면 향후 버전의 SQL Server에서는 IDENTITY 속성이 필요하지 않을 것으로 예상 할 수 있습니다. 쿼리 계획에 따라 더 이상 소스 행 세트에 다른 IDENTITY 열이 없으므로 제거되었습니다. 즉, 위의 쿼리는 어느 시점에서 예상대로 작동하지 않을 수 있습니다.

그러나 ypercubeᵀᴹ 에서 올바르게 지적한 바와 같이 지금까지 매뉴얼 은 조인이 있으면 IDENTITY 속성이 유지되지 않는다고 명시 적으로 설명했습니다.

기존 ID 열이 새 테이블로 선택되면 SELECT 문에 조인이 포함되어 있지 않으면 새 열이 IDENTITY 속성을 상속합니다.

따라서 매뉴얼에서 계속 언급하는 한, 동작이 동일하게 유지 될 것입니다.

했네 Shaneisypercubeᵀᴹ 채팅에서 관련 항목을 데리고합니다.


겠습니까 JOIN (SELECT 1) AS dummy ON 1 = 1도 작동?
ypercubeᵀᴹ


5

이 코드를 사용해보십시오.

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

ISNULL호출은 새 열이 만들어집니다 보장 NOT NULLNull 허용.


1
그것은인가 ISNULL()또는 +0그것을 않습니다? 아니면 둘 다 필요합니까?
ypercubeᵀᴹ

3

다른 방법을 보여주기 위해 :

연결된 서버를 사용할 수 있습니다 .

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

다음을 사용하여 로컬 서버에 연결된 서버를 임시로 만들 수 있습니다.

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;

어느 시점 select * into에서 localserver링크 된 서버 four-part-name을 참조하여 코드를 실행합니다 .

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

완료되면 다음을 사용하여 localserver연결된 서버를 정리 하십시오.

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

또는 OPENQUERY구문을 사용할 수 있습니다

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

1

select 문에 조인이 포함되어 있으면 identity 속성이 전송되지 않으므로

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

속성을 id유지하지 않기 위해 복사 된 열의 원하는 동작을 제공 IDENTITY하지만 행을 전혀 복사하지 않으면 부작용이 발생합니다 (다른 방법과 마찬가지로). 따라서 다음을 수행해야합니다.

insert into without_id select * from with_id;

(AakashM 감사합니다!)


1

쉬운 방법은 열을 표현식의 일부로 만드는 것입니다.

예 :
테이블 dbo.Employee에 ID 열에 대한 ID가있는 경우 아래 예에서 임시 테이블 #t에 ID ID에 대한 IDENTITY도 있습니다.

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

ID에 표현식을 적용하려면 이것을 변경하면 #t는 더 이상 ID 열에 IDENTITY가 없습니다. 이 경우 ID 열에 간단한 추가를 적용합니다.

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

다른 데이터 형식에 대한 식의 다른 예로는 convert (), 문자열 연결 또는 Isnull ()이 있습니다.


1
에서 docs.microsoft.com/en-us/sql/t-sql/queries/... : 다음 조건 중 하나에 해당하지 않는 한 "기존의 ID 열이 새 테이블로 선택하면, 새 열은 IDENTITY 속성을 상속 … 식별 컬럼은 표현식의 일부입니다.… IDENTITY 특성을 상속하는 대신 컬럼이 NOT NULL로 작성됩니다.”
Manngo

1

때로는 IDENTITY를 사용하여 열을 만들 었는지 여부를 알지 못하는 테이블에서 삽입하려고 할 때가 있습니다. 작업중인 정수 열이 아닐 수도 있습니다. 이 경우 다음이 작동합니다.

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 속성을 제거하지만 원래 열과 동일한 이름 및 유형으로 삽입하고 널 입력 가능하지 않게합니다. TOP (0)은 선택된 행을 삽입하는 데 사용할 수있는 빈 테이블을 만듭니다. 필요한 경우 데이터를 삽입하기 전에 테이블을 압축 할 수도 있습니다.


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

정체성을 제거합니다.

단점은 idNull을 허용하지만 해당 제약 조건을 추가 할 수 있다는 것입니다.


1
당신은 할 ISNULL을 사용할 수 있습니다 주위에 얻을 것을.
Erik Darling

-2

당신은하지 않습니다. select * into정체성을 보존합니다.


2
사용할 질문에 대한 요구 사항이 없습니다 *.
Martin Smith

2
그리고 identity다른 답변이 지적했듯이 재산이 항상 보존되는 것은 아닙니다.
ypercubeᵀᴹ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.