테이블의 열에서 ID 제거


127

5GB 테이블 (거의 5 억 행)이 있고 열 중 하나에서 ID 속성을 제거하려고하지만 SSMS를 통해이 작업을 수행하려고하면 시간이 초과됩니다.

T-SQL을 통해이 작업을 수행 할 수 있습니까?


1
여기에 테이블의 스키마를 게시 할 수 있습니까?
Al W

SQL Server가 간단한 ALTER TABLE ... 문을 통해 열에서 ID 속성을 제거하는 것을 지원하지 않는 훌륭한 이유가 있다고 확신하지만, 그럼에도 불구하고 현재 그 사실이 저를 슬프게합니다.
Jon Schneider

답변:


143

IDENTITY일단 설정되면 사양을 제거 할 수 없습니다 .

전체 열을 제거하려면 :

ALTER TABLE yourTable
DROP COLUMN yourCOlumn;

여기 에 ALTER TABLE 에 대한 정보

데이터를 유지해야하지만 IDENTITY열을 제거 해야하는 경우 다음을 수행해야합니다.

  • 새 열 만들기
  • 기존 IDENTITY열의 데이터를 새 열로 전송
  • 기존 IDENTITY열을 삭제하십시오 .
  • 새 열의 이름을 원래 열 이름으로 바꿉니다.

3
ID 사양을 제거 할 수 있습니다. 사실 어제 SSMS를 사용하여 5 억 개의 행이 아니었지만해야했습니다.
사이먼

33
@simon 변경 사항을 스크립팅하면 SSMS가 실제로 identity 속성없이 테이블 복사본을 만드는 것을 볼 수 있습니다.
Code Magician 2011

3
새 열의 이름을 원래 열의 이름으로 변경하기 위해 추가하고 싶습니다. 또한이 identity열이 foreign key다른 테이블의 일부로 사용되는 경우 먼저 제약 조건을 삭제 한 다음 @AdamWenger가 ID 제거에 대해 언급 한대로 조치를 취해야 attribute/property합니다. 자세한 내용은이 링크를 참조 할 수도 있습니다. 속성 만 제거하는 방법 : blog.sqlauthority.com/2009/05/03/… .. 행운을 빕니다!
Nonym 2011

1
반대 투표를 한 사람에게-내 답변에 대해 싫어하는 점을 들어 주셔서 감사합니다.
Adam Wenger

1
아래 Mark Sowul의 대답을 살펴보십시오. 열에서 열로 데이터를 이동할 필요가 없습니다. Mark의 대답을 사용하면 메타 데이터를 섞는 것입니다. 수천 또는 수억 개의 행이있는 테이블에서 작업하지 않는 한 큰 문제가 아닙니다. Plus Mark의 대답은 테이블 스키마에서 열의 재배치를 방지합니다. 방금 시도했는데 매력처럼 작동했습니다. 매우 영리한.
Andrew Steitz

100

이 작업을 수행하려면 추가하고 새 열을 채우지 않고 , 열을 재정렬없이 하고, 중단 시간없이 어떤 파티션이 사용되지 않기 때문에 데이터가 테이블에 변경되지 않기 때문에,하자가 기능을 분할하여 마법을 (하지만 당신은 돈 ' 엔터프라이즈 에디션 필요) :

  1. 이 테이블을 가리키는 모든 외래 키 제거
  2. 생성 할 테이블을 스크립팅합니다. 예를 들어 'MyTable2', 'MyIndex2'등과 같은 모든 이름을 바꿉니다. IDENTITY 사양을 제거합니다.
  3. 이제 두 개의 "동일한"테이블이 있어야합니다. 하나는 가득 차고 다른 하나는 IDENTITY없이 비어 있습니다.
  4. 운영 ALTER TABLE [Original] SWITCH TO [Original2]
  5. 이제 원래 테이블이 비어 있고 새 테이블에 데이터가 있습니다. 두 테이블의 메타 데이터를 전환했습니다 (인스턴트).
  6. 원본 (현재 비어있는 테이블)을 삭제하고 exec sys.sp_rename다양한 스키마 개체의 이름을 다시 원래 이름으로 바꾼 다음 외래 키를 다시 만들 수 있습니다.

예를 들면 다음과 같습니다.

CREATE TABLE Original
(
  Id INT IDENTITY PRIMARY KEY
, Value NVARCHAR(300)
);
CREATE NONCLUSTERED INDEX IX_Original_Value ON Original (Value);

INSERT INTO Original
SELECT 'abcd'
UNION ALL 
SELECT 'defg';

다음을 수행 할 수 있습니다.

--create new table with no IDENTITY
CREATE TABLE Original2
(
  Id INT PRIMARY KEY
, Value NVARCHAR(300)
);
CREATE NONCLUSTERED INDEX IX_Original_Value2 ON Original2 (Value);

--data before switch
SELECT 'Original', *
FROM Original
UNION ALL
SELECT 'Original2', *
FROM Original2;

ALTER TABLE Original SWITCH TO Original2;

--data after switch
SELECT 'Original', *
FROM Original
UNION ALL
SELECT 'Original2', *
FROM Original2;

--clean up 
IF NOT EXISTS (SELECT * FROM Original) DROP TABLE Original;
EXEC sys.sp_rename 'Original2.IX_Original_Value2', 'IX_Original_Value', 'INDEX';
EXEC sys.sp_rename 'Original2', 'Original', 'OBJECT';


UPDATE Original
SET Id = Id + 1;

SELECT *
FROM Original;

실제로 시도 할 시간이 없지만 다음에 정말로 정체성을 삭제해야 할 때를 아는 것은 좋은 일입니다.
CoderDennis

11
이것은 받아 들여진 대답이어야합니다. 대규모 데이터 마이그레이션없이 ID 열을 제거하는 유일한 방법입니다.
Vaccano

와! 이것은 매우 영리합니다.
Andrew Steitz

이 대답은 놀랍습니다! 감사!
Jon

5
SQL Management Studio를 사용하여 테이블을 스크립팅하는 경우 도구> 옵션> SQL Server 개체 탐색기> 스크립팅> 테이블 및보기 옵션> 스크립트 인덱스 (기본적으로 거짓)를
켜야합니다

61

외래 및 기본 키 제약 조건이 복잡해 지므로 다음과 같은 방법으로 도움이 될 몇 가지 스크립트가 있습니다.

먼저 임시 이름으로 중복 열을 만듭니다.

alter table yourTable add tempId int NOT NULL default -1;
update yourTable set tempId = id;

다음으로 기본 키 제약 조건의 이름을 가져옵니다.

SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'yourTable';

이제 열에 대한 기본 키 제약 조건을 삭제하십시오.

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;

외래 키가 있으면 실패하므로 외래 키 제약 조건을 삭제하십시오. 이 작업을 실행하는 테이블을 추적하여 나중에 제약 조건을 다시 추가 할 수 있습니다 !!!

SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'otherTable';
alter table otherTable drop constraint fk_otherTable_yourTable;
commit;
..

모든 외래 키 제약 조건이 제거되면 PK 제약 조건을 제거하고 해당 열을 삭제하고 임시 열의 이름을 바꾸고 해당 열에 PK 제약 조건을 추가 할 수 있습니다.

ALTER TABLE yourTable DROP CONSTRAINT PK_yourTable_id;
alter table yourTable drop column id;
EXEC sp_rename 'yourTable.tempId', 'id', 'COLUMN';
ALTER TABLE yourTable ADD CONSTRAINT PK_yourTable_id PRIMARY KEY (id) 
commit;

마지막으로 FK 제약 조건을 다시 추가합니다.

alter table otherTable add constraint fk_otherTable_yourTable foreign key (yourTable_id) references yourTable(id);
..

엘핀!


SQL Server 버전에주의하십시오. Azure SQL Server에서 시도했지만 여기의 모든 작업이 Azure 버전 SQL에서 지원되는 것은 아닙니다.
dasons

답변 해주셔서 감사합니다! 나를 많이 도왔다! 열을 참조하는 인덱스에 대한 확인 만 추가해야합니다. 뭔가 같은 : Select t.name 'Table', i.name 'Index', c.name 'Column', i.is_primary_key, i.is_unique From sys.tables t Inner Join sys.indexes i On i.object_id = t.object_id Inner Join sys.index_columns ic ON ic.object_id = i.object_id And i.index_id = ic.index_id Inner Join sys.columns c ON ic.object_id = c.object_id and ic.column_id = c.column_id Where t.name = 'tableName' Order By t.name, i.name, i.index_id, ic.index_column_id
알렉상드르 Junges

좋은 트릭, 많은 도움이되었지만 여기서 언급하고 싶은 점은 1 단계에서 언급 한 것처럼 새로운 중복 열을 추가 할 때 마지막에 추가되었지만 일반적으로 기본 키 열, 즉 Id가 해당 테이블의 첫 번째 열. 이에 대한 해결 방법이 있습니까?
인 Ashish Shukla

19

나는이 같은 문제가 있었다. GUI를 사용하는 대신 SSMS에서 4 개의 명령문을 사용하며 매우 빠릅니다.

  • 새 열 만들기

    alter table users add newusernum int;

  • 값 복사

    update users set newusernum=usernum;

  • 이전 열 삭제

    alter table users drop column usernum;

  • 새 열의 이름을 이전 열 이름으로 바꿉니다.

    EXEC sp_RENAME 'users.newusernum' , 'usernum', 'COLUMN';


이전 열에 대한 제약 조건이 있으면 그렇게 간단하지 않습니다.
Suncat2000

13

다음 스크립트는 'Id'라는 열의 ID 필드를 제거합니다.

도움이 되었기를 바랍니다.

BEGIN TRAN
BEGIN TRY
    EXEC sp_rename '[SomeTable].[Id]', 'OldId';

    ALTER TABLE [SomeTable] ADD Id int NULL

    EXEC ('UPDATE [SomeTable] SET Id = OldId')

    ALTER TABLE [SomeTable] NOCHECK CONSTRAINT ALL

    ALTER TABLE [SomeTable] DROP CONSTRAINT [PK_constraintName];
    ALTER TABLE [SomeTable] DROP COLUMN OldId
    ALTER TABLE [SomeTable] ALTER COLUMN [Id] INTEGER NOT NULL
    ALTER TABLE [SomeTable] ADD CONSTRAINT PK_JobInfo PRIMARY KEY (Id)

    ALTER TABLE [SomeTable] CHECK CONSTRAINT ALL

    COMMIT TRAN
END TRY
BEGIN CATCH
    ROLLBACK TRAN   
    SELECT ERROR_MESSAGE ()
END CATCH

4

식별 열 이름을 모르는 경우 벨로우 코드가 정상적으로 작동 합니다.

.NET과 같은 새 임시 테이블에 데이터를 복사해야합니다 Invoice_DELETED. 다음에 사용할 때 :

insert into Invoice_DELETED select * from Invoice where ...


SELECT t1.*
INTO Invoice_DELETED
FROM Invoice t1
LEFT JOIN Invoice ON 1 = 0
--WHERE t1.InvoiceID = @InvoiceID

자세한 설명은 https://dba.stackexchange.com/a/138345/101038을 참조하십시오.


1
사랑 YAAAAAAAAAA. 정확히 무엇을 나는 "SELECT * INTO"에서 피할 생성 "IDENTITY"에 쉬운 방법을 찾고 있었다 (백업을위한 새 테이블 온도를 만들 필요가)
KurzedMetal

그것은 작은 아름다움)
Zolfaghari

3
ALTER TABLE tablename add newcolumn int
update tablename set newcolumn=existingcolumnname
ALTER TABLE tablename DROP COLUMN existingcolumnname;
EXEC sp_RENAME 'tablename.oldcolumn' , 'newcolumnname', 'COLUMN'

그러나 위의 코드는 기본-외래 키 관계가없는 경우에만 작동합니다.


1

내가 한 똑같은 문제를 가진 사람을 위해서. 한 번만 삽입하고 싶다면 이와 같은 것을 할 수 있습니다.

두 개의 열이있는 테이블이 있다고 가정 해 보겠습니다.

ID Identity (1,1) | Name Varchar

ID = 4 인 행을 삽입하려고합니다. 따라서 3으로 다시 시드하여 다음 행이 4가되도록합니다.

DBCC CHECKIDENT([YourTable], RESEED, 3)

삽입물 만들기

INSERT  INTO [YourTable]
        ( Name )
VALUES  ( 'Client' )

그리고 시드를 가장 높은 ID로 되돌리고 15라고 가정합니다.

DBCC CHECKIDENT([YourTable], RESEED, 15)

끝난!


1

나는 동일한 요구 사항을 가지고 있었고, 개인적으로 추천하는 방법으로 시도해 볼 수 있습니다. 수동으로 테이블을 디자인하고 스크립트를 생성하십시오. 아래에서 내가 한 일은 이전 테이블의 이름과 백업에 대한 제약 조건을 변경하는 것입니다.

/* To prevent any potential data loss issues, you should review this script in detail before running it outside the context of the database designer.*/
BEGIN TRANSACTION

SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.SI_Provider_Profile
    DROP CONSTRAINT DF_SI_Provider_Profile_SIdtDateTimeStamp
GO
ALTER TABLE dbo.SI_Provider_Profile
    DROP CONSTRAINT DF_SI_Provider_Profile_SIbHotelPreLoaded
GO
CREATE TABLE dbo.Tmp_SI_Provider_Profile
    (
    SI_lProvider_Profile_ID int NOT NULL,
    SI_lSerko_Integrator_Token_ID int NOT NULL,
    SI_sSerko_Integrator_Provider varchar(50) NOT NULL,
    SI_sSerko_Integrator_Profile varchar(50) NOT NULL,
    SI_dtDate_Time_Stamp datetime NOT NULL,
    SI_lProvider_ID int NULL,
    SI_sDisplay_Name varchar(10) NULL,
    SI_lPurchased_From int NULL,
    SI_sProvider_UniqueID varchar(255) NULL,
    SI_bHotel_Pre_Loaded bit NOT NULL,
    SI_sSiteName varchar(255) NULL
    )  ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile SET (LOCK_ESCALATION = TABLE)
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
    DF_SI_Provider_Profile_SIdtDateTimeStamp DEFAULT (getdate()) FOR SI_dtDate_Time_Stamp
GO
ALTER TABLE dbo.Tmp_SI_Provider_Profile ADD CONSTRAINT
    DF_SI_Provider_Profile_SIbHotelPreLoaded DEFAULT ((0)) FOR SI_bHotel_Pre_Loaded
GO
IF EXISTS(SELECT * FROM dbo.SI_Provider_Profile)
        EXEC('INSERT INTO dbo.Tmp_SI_Provider_Profile (SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName)
        SELECT SI_lProvider_Profile_ID, SI_lSerko_Integrator_Token_ID, SI_sSerko_Integrator_Provider, SI_sSerko_Integrator_Profile, SI_dtDate_Time_Stamp, SI_lProvider_ID, SI_sDisplay_Name, SI_lPurchased_From, SI_sProvider_UniqueID, SI_bHotel_Pre_Loaded, SI_sSiteName FROM dbo.SI_Provider_Profile WITH (HOLDLOCK TABLOCKX)')
GO

-- Rename the primary key constraint or unique key In SQL Server constraints such as primary keys or foreign keys are objects in their own right, even though they are dependent upon the "containing" table.
EXEC sp_rename 'dbo.SI_Provider_Profile.PK_SI_Provider_Profile', 'PK_SI_Provider_Profile_Old';
GO
-- backup old table in case of 
EXECUTE sp_rename N'dbo.SI_Provider_Profile', N'SI_Provider_Profile_Old', 'OBJECT'
GO

EXECUTE sp_rename N'dbo.Tmp_SI_Provider_Profile', N'SI_Provider_Profile', 'OBJECT'
GO

ALTER TABLE dbo.SI_Provider_Profile ADD CONSTRAINT
    PK_SI_Provider_Profile PRIMARY KEY NONCLUSTERED 
    (
    SI_lProvider_Profile_ID
    ) WITH( PAD_INDEX = OFF, FILLFACTOR = 90, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

GO
COMMIT TRANSACTION

1

SQL Server에서 다음과 같이 ID 삽입을 켜고 끌 수 있습니다.

SET IDENTITY_INSERT table_name ON

-여기에서 쿼리 실행

SET IDENTITY_INSERT table_name OFF

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.