답변:
귀하의 질문을 이해하는 방법은 지금까지 수동 값으로 채워진 열이있는 기존 테이블이 있고 (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
삭제하고 다시 만드는 열에 따라 달라질 수있는 다른 사항을 생각해보십시오 . 기본 키로 수행 한 것처럼 모든 인덱스를 삭제하고 다시 만들어야합니다. 미리 다시 작성해야하는 모든 색인 및 제한 조건을 스크립팅해야합니다.
어떤 해제 INSERT
및 DELETE
테이블에 트리거를.
테이블을 다시 작성하는 것이 옵션 인 경우 :
테이블을 다시 만드는 것이 옵션이라면 모든 것이 훨씬 간단합니다.
id
하여 AS 열 IDENTITY
,IDENTITY_INSERT ON
테이블에 설정IDENTITY_INSERT OFF
하고IDENTITY_INSERT ON
하고 채우고 비활성화 할 수 있습니다. 그것이 내가하고 싶었지만 MSSQL이 그것을 지원하는지 몰랐습니다.
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)
유일한 문제 idT
는 IDENTITY(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
이 기술을 사용하려면 외래 키를 제거해야합니다.
idT
와 idT_Switch
테이블은 호환되는 구조를 가지고있다. 대신에 사용하는 DELETE
, UPDATE
그리고 INSERT
행을 이동하는 문 idT
에 idT_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
기술 에 대한 더 많은 배경을 가진 관련 질문과 답변이 있습니다.
새로운 아이덴티티 값으로 시작하려면 아이덴티티를 다시 시드해야합니다. 에 대한 설명서를 살펴보십시오CHECKIDENT
DBCC CHECKIDENT (yourtable, reseed, starting point)
IDENTITY
합니까?