TSQL을 사용하여 데이터베이스의 모든 테이블을 어떻게 자르나요?


204

테스트주기가 시작될 때 새 데이터로 다시로드하려는 데이터베이스에 대한 테스트 환경이 있습니다. 전체 데이터베이스를 재 구축하는 데 관심이 없으며 단순히 데이터를 "재설정"합니다.

TSQL을 사용하여 모든 테이블에서 모든 데이터를 제거하는 가장 좋은 방법은 무엇입니까? 사용할 수있는 시스템 저장 프로 시저, 뷰 등이 있습니까? 각 테이블에 대해 잘리는 테이블 문을 수동으로 생성하고 유지 관리하고 싶지 않습니다. 동적 테이블을 선호합니다.

답변:


188

SQL 2005의 경우

EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'

20002005/2008에 대한 더 많은 링크 ..


62
외래 키가있는 테이블을자를 수 없으므로 테이블간에 외래 키 제약 조건이 없거나 비활성화 된 경우에만 작동합니다.
marcj

1
agreed..i 그는 특히 테이블을 절단을 요구하기 때문에, 그는 이미 외국 키를 사용하여 문제를 해결 생각 ..
굴자는 나짐에게

@ gulzar- 일종의-나는 FK를 처리하는 방법에 대한 별도의 질문을 게시했지만 귀하의 답변은 그 자체의 장점에 있습니다.
Ray

11
@Sam : 아니요, 그렇지 않습니다! 테이블의 데이터는 관련이 없습니다. 테이블을 참조하는 외래 키 제약 조건 (비활성화 된 테이블 포함)이있는 한 테이블을자를 수 없습니다.
TToni

3
'EXEC sp_MSForEachTable'DROP TABLE? ' 잘 작동 :) (데이터베이스에서 모든 테이블을 즐겁게)
kuncevic.dev

418

외래 키 관계가있는 테이블에서 데이터를 삭제하는 경우 (기본적으로 올바르게 디자인 된 데이터베이스의 경우) 모든 제약 조건을 비활성화하고 모든 데이터를 삭제 한 다음 제약 조건을 다시 활성화 할 수 있습니다

-- disable all constraints
EXEC sp_MSForEachTable "ALTER TABLE ? NOCHECK CONSTRAINT all"

-- delete data in all tables
EXEC sp_MSForEachTable "DELETE FROM ?"

-- enable all constraints
exec sp_MSForEachTable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

제약 조건 및 트리거 비활성화에 대한 추가 정보 여기를 참조하십시오.

일부 테이블에 ID 열이있는 경우 다시 열어야 할 수도 있습니다.

EXEC sp_MSForEachTable "DBCC CHECKIDENT ( '?', RESEED, 0)"

RESEED의 동작은 새 테이블과 이전에 BOL 에서 일부 데이터를 삽입 한 테이블간에 다릅니다 .

DBCC CHECKIDENT ( 'table_name', RESEED, newReseedValue)

현재 ID 값은 newReseedValue로 설정됩니다. 작성된 이후 테이블에 행이 삽입되지 않은 경우 DBCC CHECKIDENT를 실행 한 후 삽입 된 첫 번째 행은 newReseedValue를 ID로 사용합니다. 그렇지 않으면 삽입 된 다음 행은 newReseedValue + 1을 사용합니다. newReseedValue의 값이 ID 열의 최대 값보다 작은 경우, 테이블에 대한 후속 참조에서 오류 메시지 2627이 생성됩니다.

제약 조건을 비활성화하면 자르기를 사용할 수 없다는 사실을 지적한 Robert 에게 감사의 말을 전하고 제약 조건을 삭제 한 다음 다시 만들어야합니다.


34
제약 조건을 비활성화하면 FOREIGN KEY 제약 조건에서 참조하는 테이블을자를 수 없습니다. FK 제약 조건을 삭제해야합니다. 이것에 대해 틀렸다면 답장을 보내십시오. 그러나 삭제하지 않는 방법을 찾지 못했습니다.
Robert Claypool

1
EXEC sp_MSForEachTable "DELETE FROM TABLE?"문에 오타 "Table"키워드 만 있으면 안됩니다. . 올바른 버전은 다음과 같아야합니다. EXEC sp_MSForEachTable "DELETE FROM?"
Raghav

4
2008 이상의 SSMS를 사용하는 경우 SET ROWCOUNT 0기본적으로 작업을 500 행으로 제한하는 것이기 때문에 스크립트 시작 부분에 추가하고 싶을 것입니다 ! 모든 데이터가 실제로 삭제되지는 않았기 때문에 좌절 한 오류가 발생합니다.
Sean Hanley

1
이것은 훌륭하게 작동했습니다. 필자의 경우에는 delete 문 전후에 EXEC sp_msforeachtable "ALTER TABLE? TRIGGER all 사용 안 함"및 EXEC sp_msforeachtable "ALTER TABLE? TRIGGER all 사용"을 추가해야했습니다.
RobC

2
내가 가장 좋아하는 답변. 그러나 왜 (모든 주석 작성자조차) 리터럴 SQL 문자열을 큰 따옴표로 묶습니까?
bitoolean

57

다음은 데이터베이스 삭제 스크립트의 왕자입니다. 모든 테이블을 지우고 올바르게 다시 시드합니다.

SET QUOTED_IDENTIFIER ON;
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? NOCHECK CONSTRAINT ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? DISABLE TRIGGER ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? CHECK CONSTRAINT ALL'  
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? ENABLE TRIGGER ALL' 
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON';

IF NOT EXISTS (
    SELECT
        *
    FROM
        SYS.IDENTITY_COLUMNS
        JOIN SYS.TABLES ON SYS.IDENTITY_COLUMNS.Object_ID = SYS.TABLES.Object_ID
    WHERE
        SYS.TABLES.Object_ID = OBJECT_ID('?') AND SYS.IDENTITY_COLUMNS.Last_Value IS NULL
)
AND OBJECTPROPERTY( OBJECT_ID('?'), 'TableHasIdentity' ) = 1

    DBCC CHECKIDENT ('?', RESEED, 0) WITH NO_INFOMSGS;

즐기 되 조심하십시오!


2
sp_MSforeachtable이 SET QUOTED_IDENTITY OFF해당 본문에 포함되어 있기 때문에 열을 계산 한 경우 불행히도 위 명령이 실패합니다 ( link ). 업데이트 : 수정은 "SET QUOTED_IDENTIFIERS on;"을 추가하는 것입니다. 이 오류를 발생시키는 각 진술의 시작 부분까지 ( 여기 에서 언급 한 바와 같이 )
Marchy

1
이건 내 정체성을
앗아 가지

48

가장 간단한 방법은

  1. SQL Management Studio를 엽니 다
  2. 데이터베이스로 이동
  3. 마우스 오른쪽 단추를 클릭하고 태스크-> 스크립트 생성을 선택하십시오 (그림 1).
  4. "객체 선택"화면에서 "특정 객체 선택"옵션을 선택하고 "테이블"을 확인하십시오 (그림 2).
  5. 다음 화면에서 "고급"을 선택한 다음 "스크립트 DROP 및 작성"옵션을 "스크립트 DROP 및 작성"으로 변경하십시오 (그림 3).
  6. 스크립트를 새 편집기 창 또는 파일에 저장하고 필요에 따라 실행하도록 선택하십시오.

이렇게하면 디버깅이나 모든 것을 포함했는지에 대해 걱정할 필요없이 모든 테이블을 삭제하고 다시 만드는 스크립트가 제공됩니다. 이것은 잘림 이상의 기능을 수행하지만 결과는 동일합니다. 할당 된 마지막 값을 기억하는 잘린 테이블과 달리 자동 증가 기본 키는 0에서 시작합니다. PreProd 또는 프로덕션 환경에서 Management Studio에 액세스 할 수없는 경우 코드에서이를 실행할 수도 있습니다.

1.

여기에 이미지 설명을 입력하십시오

2.

여기에 이미지 설명을 입력하십시오

삼.

여기에 이미지 설명을 입력하십시오


1
매우 복잡한 스키마가있는 데이터베이스에 이것을 사용하는 경우주의하십시오. 프로덕션 DB의 개발자 사본에서 시도해 보았고 스키마를 폐기하여 완전히 재배치해야했습니다.
Techrocket9

1
당신은 당신이 보존하고자하는 모든 것을 스크립트해야합니다
선장 Kenpachi

13

SQL Server에서는 외래 키를 사용하여 테이블을자를 수 없으므로 테이블간에 외래 키 관계가없는 경우에만 모든 테이블을 잘릴 수 있습니다.

이에 대한 대안은 외래 키가있는 테이블을 결정하고 먼저 외래 키를 삭제하는 것입니다. 그런 다음 외래 키없이 테이블을자를 수 있습니다.

자세한 내용은 http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=65341http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72957 을 참조 하십시오 .


1
좋은 지적. 그렇게 생각하지 않았습니다. 모든 제약 조건을 먼저 비활성화 한 다음 데이터가 제거되면 다시 제약 조건을 활성화 할 수 있습니다.
Ray

7

MSSQL Server Deveploper 또는 Enterprise와 함께 사용하는 다른 옵션은 빈 스키마를 만든 직후 데이터베이스의 스냅 샷을 만드는 것입니다. 이 시점에서 데이터베이스를 계속 스냅 샷으로 복원 할 수 있습니다.


불행히도 매번 모든 FULLTEXT 지수를 잃습니다
Chris KL

6

이러지 마! 실제로는 좋은 생각이 아닙니다.

잘라내려는 테이블을 알고있는 경우 잘리는 저장 프로 시저를 만듭니다. 외래 키 문제를 피하기 위해 순서를 수정할 수 있습니다.

실제로 모두 잘라내려면 (예를 들어 BCP를로드 할 수 있음) 데이터베이스를 신속하게 삭제하고 처음부터 새 데이터베이스를 작성하면 위치를 정확히 알 수있는 추가 이점이 있습니다.


여기에 좋은 대안이 있습니다.
Sam

3
접근 방식의 문제점은 테이블과 데이터베이스를 삭제하면 다른 로그인 및 스키마에 부여 된 모든 권한이 손실된다는 것입니다. 이를 다시 만들려면 테이블이 많은 대규모 데이터베이스에서 어려움을 겪을 것입니다.
Punit Vora

4

동일한 db 내에서 다른 테이블의 데이터를 삭제 / 잘라내는 동안 특정 테이블 (예 : 정적 조회 테이블)에 데이터를 유지하려면 예외가있는 루프가 필요합니다. 이것이 내가이 질문을 우연히 발견했을 때 찾고 있던 것입니다.

sp_MSForEachTable은 버그가있는 것 같습니다 (즉, IF 문과 일치하지 않는 동작). 아마도 MS가 문서화하지 않은 이유 일 것입니다.

declare @LastObjectID int = 0
declare @TableName nvarchar(100) = ''
set @LastObjectID = (select top 1 [object_id] from sys.tables where [object_id] > @LastObjectID order by [object_id])
while(@LastObjectID is not null)
begin
    set @TableName = (select top 1 [name] from sys.tables where [object_id] = @LastObjectID)

    if(@TableName not in ('Profiles', 'ClientDetails', 'Addresses', 'AgentDetails', 'ChainCodes', 'VendorDetails'))
    begin
        exec('truncate table [' + @TableName + ']')
    end 

    set @LastObjectID = (select top 1 [object_id] from sys.tables where [object_id] > @LastObjectID order by [object_id])
end

4

모든 테이블을 잘라내는 가장 어려운 부분은 외래 키 제약 조건을 제거하고 다시 추가하는 것입니다.

다음 쿼리는 @myTempTable의 각 테이블 이름과 관련된 각 제약 조건에 대해 drop & create 문을 만듭니다. 모든 테이블에 대해 이들을 생성하려면 정보 스키마를 사용하여 이러한 테이블 이름을 대신 수집 할 수 있습니다.

DECLARE @myTempTable TABLE (tableName varchar(200))
INSERT INTO @myTempTable(tableName) VALUES
('TABLE_ONE'),
('TABLE_TWO'),
('TABLE_THREE')


-- DROP FK Contraints
SELECT 'alter table '+quotename(schema_name(ob.schema_id))+
  '.'+quotename(object_name(ob.object_id))+ ' drop constraint ' + quotename(fk.name) 
  FROM sys.objects ob INNER JOIN sys.foreign_keys fk ON fk.parent_object_id = ob.object_id
  WHERE fk.referenced_object_id IN 
      (
         SELECT so.object_id 
         FROM sys.objects so JOIN sys.schemas sc
         ON so.schema_id = sc.schema_id
         WHERE so.name IN (SELECT * FROM @myTempTable)  AND sc.name=N'dbo'  AND type in (N'U'))


 -- CREATE FK Contraints
 SELECT 'ALTER TABLE [PIMSUser].[dbo].[' +cast(c.name as varchar(255)) + '] WITH NOCHECK ADD CONSTRAINT ['+ cast(f.name as varchar(255)) +'] FOREIGN KEY (['+ cast(fc.name as varchar(255)) +'])
      REFERENCES [PIMSUser].[dbo].['+ cast(p.name as varchar(255)) +'] (['+cast(rc.name as varchar(255))+'])'
FROM  sysobjects f
      INNER JOIN sys.sysobjects c ON f.parent_obj = c.id
      INNER JOIN sys.sysreferences r ON f.id = r.constid
      INNER JOIN sys.sysobjects p ON r.rkeyid = p.id
      INNER JOIN sys.syscolumns rc ON r.rkeyid = rc.id and r.rkey1 = rc.colid
      INNER JOIN sys.syscolumns fc ON r.fkeyid = fc.id and r.fkey1 = fc.colid
WHERE 
      f.type = 'F'
      AND
      cast(p.name as varchar(255)) IN (SELECT * FROM @myTempTable)

그런 다음 실행할 명령문을 복사하지만 약간의 노력으로 커서를 사용하여 동적으로 실행할 수 있습니다.


3

데이터베이스를 스크립팅하는 것이 훨씬 쉽고 (아마도 빠를 수 있음) 스크립트에서 데이터베이스를 삭제하고 작성하기 만하면됩니다.


3

비어있는 "템플릿"데이터베이스를 만들고 전체 백업을 수행하십시오. 새로 고침해야 할 때는 WITH REPLACE를 사용하여 복원하십시오. 빠르고 간단하며 방탄. 그리고 여기에 몇 개의 테이블이 있거나 기본 데이터 (예 : 구성 정보 또는 앱을 실행시키는 기본 정보)가 필요한 경우도 처리합니다.


2

이것은 하나입니다 방법입니다 ... 10 가지가 더 좋고 더 효율적일 가능성이 있지만, 이것이 매우 드물게 수행되는 것처럼 들리므로 여기에갑니다 ...

tablesfrom 의 목록을 가져온 sysobjects다음 커서를 사용 sp_execsql('truncate table ' + @table_name)하여 각각을 호출 하여 목록 을 반복 합니다 iteration.


이것도 내가하는 것이기 때문에 sql로 게시물을 추가했습니다 :)
Chris Smith

1

주석 처리 된 섹션을 한 번 실행하고 _TruncateList 테이블을 잘라내려는 테이블로 채우고 나머지 스크립트를 실행하십시오. 이 작업을 많이 수행하면 시간이 지남에 따라 _ScriptLog 테이블을 정리해야합니다.

모든 테이블을 수행하려면 SELECT name INTO #TruncateList FROM sys.tables에두기 만하면이 값을 수정할 수 있습니다. 그러나 일반적으로 모든 것을 원하지는 않습니다.

또한 이것은 데이터베이스의 모든 외래 키에 영향을 미치며 응용 프로그램에 너무 무딘 경우에도 수정할 수 있습니다. 내 목적이 아닙니다.

/*
CREATE TABLE _ScriptLog 
(
    ID Int NOT NULL Identity(1,1)
    , DateAdded DateTime2 NOT NULL DEFAULT GetDate()
    , Script NVarChar(4000) NOT NULL
)

CREATE UNIQUE CLUSTERED INDEX IX_ScriptLog_DateAdded_ID_U_C ON _ScriptLog
(
    DateAdded
    , ID
)

CREATE TABLE _TruncateList
(
    TableName SysName PRIMARY KEY
)
*/
IF OBJECT_ID('TempDB..#DropFK') IS NOT NULL BEGIN
    DROP TABLE #DropFK
END

IF OBJECT_ID('TempDB..#TruncateList') IS NOT NULL BEGIN
    DROP TABLE #TruncateList
END

IF OBJECT_ID('TempDB..#CreateFK') IS NOT NULL BEGIN
    DROP TABLE #CreateFK
END

SELECT Scripts = 'ALTER TABLE ' + '[' + OBJECT_NAME(f.parent_object_id)+ ']'+
' DROP  CONSTRAINT ' + '[' + f.name  + ']'
INTO #DropFK
FROM .sys.foreign_keys AS f
INNER JOIN .sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id

SELECT TableName
INTO #TruncateList
FROM _TruncateList

SELECT Scripts = 'ALTER TABLE ' + const.parent_obj + '
    ADD CONSTRAINT ' + const.const_name + ' FOREIGN KEY (
            ' + const.parent_col_csv + '
            ) REFERENCES ' + const.ref_obj + '(' + const.ref_col_csv + ')
'
INTO #CreateFK
FROM (
    SELECT QUOTENAME(fk.NAME) AS [const_name]
        ,QUOTENAME(schParent.NAME) + '.' + QUOTENAME(OBJECT_name(fkc.parent_object_id)) AS [parent_obj]
        ,STUFF((
                SELECT ',' + QUOTENAME(COL_NAME(fcP.parent_object_id, fcp.parent_column_id))
                FROM sys.foreign_key_columns AS fcP
                WHERE fcp.constraint_object_id = fk.object_id
                FOR XML path('')
                ), 1, 1, '') AS [parent_col_csv]
        ,QUOTENAME(schRef.NAME) + '.' + QUOTENAME(OBJECT_NAME(fkc.referenced_object_id)) AS [ref_obj]
        ,STUFF((
                SELECT ',' + QUOTENAME(COL_NAME(fcR.referenced_object_id, fcR.referenced_column_id))
                FROM sys.foreign_key_columns AS fcR
                WHERE fcR.constraint_object_id = fk.object_id
                FOR XML path('')
                ), 1, 1, '') AS [ref_col_csv]
    FROM sys.foreign_key_columns AS fkc
    INNER JOIN sys.foreign_keys AS fk ON fk.object_id = fkc.constraint_object_id
    INNER JOIN sys.objects AS oParent ON oParent.object_id = fkc.parent_object_id
    INNER JOIN sys.schemas AS schParent ON schParent.schema_id = oParent.schema_id
    INNER JOIN sys.objects AS oRef ON oRef.object_id = fkc.referenced_object_id
    INNER JOIN sys.schemas AS schRef ON schRef.schema_id = oRef.schema_id
    GROUP BY fkc.parent_object_id
        ,fkc.referenced_object_id
        ,fk.NAME
        ,fk.object_id
        ,schParent.NAME
        ,schRef.NAME
    ) AS const
ORDER BY const.const_name

INSERT INTO _ScriptLog (Script)
SELECT Scripts
FROM #CreateFK

DECLARE @Cmd NVarChar(4000)
    , @TableName SysName

WHILE 0 < (SELECT Count(1) FROM #DropFK) BEGIN
    SELECT TOP 1 @Cmd = Scripts 
    FROM #DropFK

    EXEC (@Cmd)

    DELETE #DropFK WHERE Scripts = @Cmd
END

WHILE 0 < (SELECT Count(1) FROM #TruncateList) BEGIN
    SELECT TOP 1 @Cmd = N'TRUNCATE TABLE ' +  TableName
        , @TableName = TableName
    FROM #TruncateList

    EXEC (@Cmd)

    DELETE #TruncateList WHERE TableName = @TableName
END

WHILE 0 < (SELECT Count(1) FROM #CreateFK) BEGIN
    SELECT TOP 1 @Cmd = Scripts 
    FROM #CreateFK

    EXEC (@Cmd)

    DELETE #CreateFK WHERE Scripts = @Cmd
END

0

각 테이블을 삭제하고 다시 만드는 스크립트보다 데이터 지우기가 더 나은 이유를 알 수 없습니다.

빈 DB의 백업을 유지하고 오래된 DB를 복원하십시오.


2
그 이유는 데이터베이스 디스크 파일, 로그 등을 삭제하고 다시 만드는 오버 헤드가 매우 느리기 때문입니다. 적절한 단위 테스트 실행 중에 데이터베이스를 1,000 번 닦으십시오.
Chris KL

0

테이블을 자르기 전에 모든 외래 키를 제거해야합니다. 이 스크립트 를 사용 하여 데이터베이스에서 모든 외래 키를 삭제하고 다시 생성하는 최종 스크립트 를 생성 하십시오 . @action 변수를 'CREATE'또는 'DROP'로 설정하십시오.


0

INFORMATION_SCHEMA.TABLES에서 '+ TABLE_NAME에서 삭제'를 선택하십시오. 여기서 TABLE_TYPE = 'BASE TABLE'

결과가 나오는 곳.

쿼리 창에서 복사하여 붙여 넣기 및 명령 실행


0

조금 늦었지만 누군가를 도울 수 있습니다. 때때로 T-SQL을 사용하여 다음을 수행하는 프로 시저를 작성했습니다.

  1. 모든 제약 조건을 임시 테이블에 저장
  2. 모든 제약 조건 제거
  3. 잘릴 필요가없는 일부 테이블을 제외하고 모든 테이블을 자릅니다.
  4. 모든 제약 조건을 재현하십시오.

내 블로그에 여기 에 나열했습니다

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