기존 PK에 자동 증분 추가


14

다른 DB에 이미 존재하는 DB에 테이블을 만들었습니다. 처음에는 이전 DB 데이터로 채워졌습니다. 테이블의 PK는 해당 레코드에 이미 존재하는 값을 수신해야하므로 자동 증가 할 수 없었습니다.

이제 자동 증분으로 PK를 가지려면 새 테이블이 필요합니다. 그러나 PK가 이미 존재하고 데이터가있는 후에 어떻게해야합니까?


3
"자동 증가"라고 말할 때 정확히 무엇 을 말하는 것입니까? SQL Server에는 열에 대한 이러한 속성이 없습니다. 당신은 의미 IDENTITY합니까?
Max Vernon

예, 이것이 MSSQL에서 호출되는 방식입니다. 일반적으로 데이터베이스에서는 자동 증분 PK입니다.
Hikari

답변:


14

귀하의 질문을 이해하는 방법은 지금까지 수동 값으로 채워진 열이있는 기존 테이블이 있고 (1)이 열을 IDENTITY열로 만들고 (2) IDENTITY시작 을 확인하는 것입니다 기존 행의 가장 최근 값에서

먼저, 테스트 할 몇 가지 테스트 데이터 :

CREATE TABLE dbo.ident_test (
    id    int NOT NULL,
    xyz   varchar(10) NOT NULL,
    CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id)
);

INSERT INTO dbo.ident_test (id, xyz)
VALUES (1, 'test'),
       (2, 'test'),
       (5, 'test'),
       (6, 'test'),
       (10, 'test'),
       (18, 'test'),
       (19, 'test'),
       (20, 'test');

목표는 테이블의 기본 키 열 ( 삽입되는 다음 레코드의 21에서 시작 id하는 IDENTITY열)을 만드는 것입니다. 이 예에서 열 xyz은 테이블의 다른 모든 열을 나타냅니다.

무엇이든하기 전에이 게시물의 하단에있는 경고를 읽으십시오.

먼저, 무언가 잘못되었을 경우를 대비하여 :

BEGIN TRANSACTION;

이제 임시 작업 열을 추가하고 id_temp해당 열을 기존 id열의 값으로 설정하십시오.

ALTER TABLE dbo.ident_test ADD id_temp int NULL;
UPDATE dbo.ident_test SET id_temp=id;

다음으로 기존 id열 을 삭제해야합니다 ( 기존 열에 "추가"할 수 없으며 IDENTITY열을으로 만들어야 함 IDENTITY). 열이 종속되어 있기 때문에 기본 키도 이동해야합니다.

ALTER TABLE dbo.ident_test DROP CONSTRAINT PK_ident_test;
ALTER TABLE dbo.ident_test DROP COLUMN id;

... 그리고 이번에 IDENTITY는 기본 키와 함께 열을 다시 추가하십시오 .

ALTER TABLE dbo.ident_test ADD id int IDENTITY(1, 1) NOT NULL;
ALTER TABLE dbo.ident_test ADD CONSTRAINT PK_ident_test PRIMARY KEY CLUSTERED (id);

여기 흥미로운 곳이 있습니다. IDENTITY_INSERT테이블에서 활성화 할 수 있습니다. 즉, IDENTITY새 행을 삽입 할 때 (기존 행은 업데이트하지 않음) 열 값을 수동으로 정의 할 수 있습니다 .

SET IDENTITY_INSERT dbo.ident_test ON;

해당 세트를 사용하면 DELETE테이블의 모든 행이지만 삭제하는 행은 OUTPUT동일한 테이블에 있지만 id백업 열의 열에 대한 특정 값이 있습니다.

DELETE FROM dbo.ident_test
OUTPUT deleted.id_temp AS id, deleted.xyz
INTO dbo.ident_test (id, xyz);

완료되면 IDENTITY_INSERT다시 전원을 끄십시오.

SET IDENTITY_INSERT dbo.ident_test OFF;

추가 한 임시 열을 삭제하십시오.

ALTER TABLE dbo.ident_test DROP COLUMN id_temp;

마지막으로 IDENTITY열을 다시 시드하여 다음 레코드가 열 id에서 기존의 가장 높은 숫자 다음에 다시 시작 id됩니다.

DECLARE @maxid int;
SELECT @maxid=MAX(id) FROM dbo.ident_test;
DBCC CHECKIDENT ("dbo.ident_test", RESEED, @maxid)

예제 테이블을 확인하면 가장 높은 id숫자는 20입니다.

SELECT * FROM dbo.ident_test;

다른 행을 추가하고 새로운 행을 확인하십시오 IDENTITY.

INSERT INTO dbo.ident_test (xyz) VALUES ('New row');
SELECT * FROM dbo.ident_test;

이 예에서 새 행은 id=21입니다. 마지막으로, 행복하다면 트랜잭션을 커밋하십시오.

COMMIT TRANSACTION;

중대한

이것은 사소한 작업이 아니며 알아야 할 몇 가지 위험이 있습니다.

  • 전용 테스트 환경에서이 작업을 수행하십시오. 백업하십시오. :)

  • 내가 사용하려는 BEGIN/COMMIT TRANSACTION당신이 그것을 변화의 중간에있는 동안 테이블 덤비는에서 다른 프로세스를 방지하기 때문에, 뭔가가 잘못되면 그것은 당신에게 롤 모든 것을 다시 할 수있는 가능성을 제공합니다. 그러나 트랜잭션을 커밋하기 전에 테이블에 액세스하려고 시도하는 다른 프로세스는 결국 대기합니다. 큰 테이블이 있거나 프로덕션 환경에있는 경우 이는 매우 나쁠 수 있습니다.

  • OUTPUT .. INTO대상 테이블에 외래 키 제약 조건이 있거나 머리 꼭대기에서 기억할 수없는 여러 가지 다른 기능이 있으면 작동하지 않습니다. 대신 데이터를 임시 테이블로 오프로드 한 다음 원래 테이블에 다시 삽입 할 수 있습니다. 파티션을 사용하지 않더라도 파티션 전환을 사용할 수 있습니다.

  • 배치 또는 저장 프로 시저가 아니라 하나씩이 명령문을 실행하십시오.

  • id삭제하고 다시 만드는 열에 따라 달라질 수있는 다른 사항을 생각해보십시오 . 기본 키로 수행 한 것처럼 모든 인덱스를 삭제하고 다시 만들어야합니다. 미리 다시 작성해야하는 모든 색인 및 제한 조건을 스크립팅해야합니다.

  • 어떤 해제 INSERTDELETE테이블에 트리거를.

테이블을 다시 작성하는 것이 옵션 인 경우 :

테이블을 다시 만드는 것이 옵션이라면 모든 것이 훨씬 간단합니다.

  • 와 빈 테이블을 작성 id하여 AS 열 IDENTITY,
  • IDENTITY_INSERT ON테이블에 설정
  • 테이블을 채우십시오.
  • 설정 IDENTITY_INSERT OFF하고
  • 아이덴티티를 시드했습니다.

좋은 답변, 많이 감사합니다! 실제로 내 경우에는을 설정 IDENTITY_INSERT ON하고 채우고 비활성화 할 수 있습니다. 그것이 내가하고 싶었지만 MSSQL이 그것을 지원하는지 몰랐습니다.
Hikari

5

UPDATE, DELETE 또는 INSERT를 사용하여 데이터를 이동하면 데이터와 로그 파일 / 디스크 모두에서 시간이 많이 걸리고 리소스 (IO)를 사용할 수 있습니다. 큰 테이블에서 작업하는 동안 트랜잭션 로그에 잠재적으로 많은 레코드를 채우는 것을 피할 수 있습니다. 파티션 전환을 사용하면 메타 데이터 만 변경됩니다.

관련된 데이터 이동이 없으므로이 작업은 실제로 거의 즉각적으로 수행됩니다.

샘플 테이블

질문에 원래 테이블 DDL이 표시되지 않습니다. 이 답변에서 다음 DDL이 예로 사용됩니다.

CREATE TABLE dbo.idT(
    id int not null
    , uid uniqueidentifier not null
    , name varchar(50)
);
ALTER TABLE dbo.idT ADD CONSTRAINT PK_idT PRIMARY KEY CLUSTERED(id);

이 쿼리를 사용하여 0에서 15까지의 더미 임의의 ID 6 개가 추가됩니다.

WITH ids(n) AS(
    SELECT x1.n+x2.n*4
    FROM (values(0), (3)) as x1(n)
    CROSS JOIN (values(0), (2), (3)) as x2(n)
)
INSERT INTO idt(id, uid, name)
SELECT n, NEWID(), NEWID() 
FROM ids

데이터 예 IdT

id  uid                                     name
0   65533096-5007-43EA-88AD-D6776B3B94FA    6A69D4F2-D682-4168-A92F-4CD2E2DBC21D
3   CE87F1ED-BE1A-4F2D-8D62-E1ECA822D35B    AF0524D9-0DBB-41E1-883B-003CB4E4F012
8   34A1DBFD-4F92-4F34-9F04-4CDC824AB15A    02B4BDA4-D515-4262-9031-0BE496AC24CE
11  51606C95-9DE8-4C30-B23B-F915EEA41156    93258103-9C22-4F9C-85CF-712ED0FB3CE6
12  CEC80431-0513-4751-A250-0EB3390DACAB    2DA6B8AF-3EBC-42B3-A76C-028716E24661
15  5037EA83-286F-4EBC-AD7C-E237B570C1FF    095E51E9-8C38-4104-858F-D14AA810A550

새로운 테이블 IDENTITY(0, 1)

유일한 문제 idTIDENTITY(0, 1)id에 속성 이 없다는 것입니다 . 구조가 비슷한 새 테이블 IDENTITY(0, 1)이 생성됩니다.

CREATE TABLE dbo.idT_Switch(
    id int identity(0, 1) not null
    , uid uniqueidentifier not null
    , name varchar(50)
);
ALTER TABLE dbo.idT_Switch ADD CONSTRAINT PK_idT_Switch PRIMARY KEY CLUSTERED(id);

이외에도에서 IDENTITY(0, 1), idT_Switch동일하다 idT.

외래 키

idT이 기술을 사용하려면 외래 키를 제거해야합니다.

파티션 스위치

idTidT_Switch테이블은 호환되는 구조를 가지고있다. 대신에 사용하는 DELETE, UPDATE그리고 INSERT행을 이동하는 문 idTidT_Switch나에 idT자체 ALTER TABLE ... SWITCH사용할 수 있습니다 :

ALTER TABLE dbo.idT
SWITCH TO dbo.idT_Switch;

PK_idT(전체 테이블) 의 단일 '파티션'이 PK_idT_Switch(및 그 반대로) 이동됩니다 . idT이제 0 행을 idT_Switch포함하고 6 행을 포함합니다.

여기에서 소스 및 대상 호환성 요구 사항의 전체 목록을 찾을 수 있습니다.

파티션 전환을 사용하여 효율적으로 데이터 전송

이 사용 참고 SWITCH명시 적 분할이 없기 때문에, Enterprise Edition을 필요로하지 않습니다. 분할되지 않은 테이블은 SQL Server 2005부터 단일 파티션이있는 테이블로 간주됩니다.

바꾸다 idT

idT 이제 비어 있고 쓸모 없으며 삭제할 수 있습니다.

DROP TABLE idT;

idT_Switch이름을 바꿀 수 있으며 이전 idT테이블 을 대체 합니다.

EXECUTE sys.sp_rename
    @objname = N'dbo.idT_Switch',
    @newname = N'idT', -- note lack of schema prefix
    @objtype = 'OBJECT';

외래 키

idT테이블에 외래 키를 다시 추가 할 수 있습니다 . idT전환을 위해 테이블을 호환 가능하게하기 위해 이전에 제거 된 모든 항목 도 다시 작성해야합니다.

시드

SELECT IDENT_CURRENT( 'dbo.idT');

이 명령은 0을 리턴합니다. 테이블 idT는 MAX (id) = 15 인 6 개의 행을 포함합니다. DBCC CHECKIDENT (table_name)를 사용할 수 있습니다.

DBCC CHECKIDENT ('dbo.idT');

15가 0보다 크므로 MAX (id)를 찾지 않고 자동으로 다시 시드됩니다.

테이블의 현재 ID 값이 ID 열에 저장된 최대 ID 값보다 작은 경우 ID 열의 최대 값을 사용하여 재설정됩니다. 다음의 '예외'섹션을 참조하십시오.

IDENT_CURRENT는 이제 15를 반환합니다 .

데이터 테스트 및 추가

간단한 INSERT진술 :

INSERT INTO idT(uid, name) SELECT NEWID(), NEWID();

이 행을 추가합니다 :

id  uid                                     name
16  B395D692-5D7B-4DFA-9971-A1497B8357A1    FF210D9E-4027-479C-B5D8-057E77FAF378

id열 이제 ID를 사용하고, 새로 삽입 한 값은 실제로 16 (15 + 1)이다.

추가 정보

SWITCH기술 에 대한 더 많은 배경을 가진 관련 질문과 답변이 있습니다.

지원되지 않는 열에서 Identity 속성을 제거하는 이유


4

새로운 아이덴티티 값으로 시작하려면 아이덴티티를 다시 시드해야합니다. 에 대한 설명서를 살펴보십시오CHECKIDENT

DBCC CHECKIDENT (yourtable, reseed, starting point)

0

IDENTITY_INSERT 활성화 및 비활성화

테이블이 TABLE_A이면

  1. 식별 컬럼이있는 TABLE_A와 유사한 CREATE TABLE TABLE_B
  2. SET IDENTITY_INSERT TABLE_B ON
  3. TABLE_A에서 TABLE_B에 INSERT
  4. SET IDENTITY_INSERT TABLE_B OFF
  5. DROP TABLE TABLE_A 및 테이블 이름 바꾸기 Exec sp_rename 'TABLE_B', 'TABLE_A'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.