Làm thế nào để bạn cắt bớt tất cả các bảng trong cơ sở dữ liệu bằng TSQL?


204

Tôi có một môi trường thử nghiệm cho cơ sở dữ liệu mà tôi muốn tải lại dữ liệu mới khi bắt đầu chu kỳ thử nghiệm. Tôi không quan tâm đến việc xây dựng lại toàn bộ cơ sở dữ liệu - chỉ đơn giản là "thiết lập lại" dữ liệu.

Cách tốt nhất để xóa tất cả dữ liệu khỏi tất cả các bảng bằng TSQL là gì? Có hệ thống lưu trữ thủ tục, quan điểm, vv có thể được sử dụng? Tôi không muốn tự tạo và duy trì các câu lệnh bảng rút gọn cho mỗi bảng - tôi muốn nó là động.

Câu trả lời:


188

Đối với SQL 2005,

EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'

Thêm vài liên kết cho 20002005/2008 ..


62
Bạn không thể cắt bớt các bảng có khóa ngoại, vì vậy điều này sẽ chỉ hoạt động nếu không có ràng buộc khóa ngoại giữa các bảng (hoặc chúng đã bị vô hiệu hóa).
marcj

1
đồng ý..tôi nghĩ từ khi anh ta đặc biệt yêu cầu cắt bớt các bảng, anh ta đã giải quyết vấn đề với khóa ngoại ..
Gulzar Nazim

@ gulzar- sort of- tôi đã đăng một câu hỏi riêng về cách xử lý các FK nhưng câu trả lời của bạn đứng trên giá trị riêng của nó.
Ray

11
@Sam: Không, nó sẽ không! Dữ liệu trong các bảng là không liên quan. Miễn là có một ràng buộc khóa ngoại tham chiếu bảng (ngay cả một bảng bị vô hiệu hóa), bạn không thể cắt bớt nó.
TToni

3
'EXEC sp_MSForEachTable' BẢNG DROP? ' Hoạt động rất tốt :) (làm hài lòng tất cả các bảng từ cơ sở dữ liệu)
kuncevic.dev

418

Khi xử lý xóa dữ liệu khỏi các bảng có mối quan hệ khóa ngoài - về cơ bản là với bất kỳ cơ sở dữ liệu nào được thiết kế đúng - chúng ta có thể vô hiệu hóa tất cả các ràng buộc, xóa tất cả dữ liệu và sau đó kích hoạt lại các ràng buộc

-- 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"

Thêm về vô hiệu hóa các ràng buộc và kích hoạt ở đây

nếu một số bảng có các cột định danh, chúng tôi có thể muốn đổi lại chúng

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

Lưu ý rằng hành vi của RESEED khác nhau giữa bảng hoàn toàn mới và bảng đã có một số dữ liệu được chèn trước đó từ BOL :

KIỂM TRA DBCC ('tên_bảng', RESEED, newReseedValue)

Giá trị nhận dạng hiện tại được đặt thành newReseedValue. Nếu không có hàng nào được chèn vào bảng kể từ khi nó được tạo, hàng đầu tiên được chèn sau khi thực hiện DBCC CHECKIDENT sẽ sử dụng newReseedValue làm danh tính. Mặt khác, hàng tiếp theo được chèn sẽ sử dụng newReseedValue + 1. Nếu giá trị của newReseedValue nhỏ hơn giá trị tối đa trong cột định danh, thông báo lỗi 2627 sẽ được tạo trên các tham chiếu tiếp theo vào bảng.

Cảm ơn Robert đã chỉ ra một thực tế là việc vô hiệu hóa các ràng buộc không cho phép sử dụng cắt ngắn, các ràng buộc sẽ phải được loại bỏ, và sau đó được tạo lại


33
Vô hiệu hóa các ràng buộc sẽ KHÔNG cho phép cắt bớt các bảng được tham chiếu bởi ràng buộc FOREIGN KEY. Các ràng buộc FK phải được loại bỏ. Vui lòng trả lời nếu tôi sai về điều này, nhưng tôi đã không tìm ra cách nào để tránh làm rơi chúng.
Robert Claypool

1
Chỉ cần một từ khóa "Bảng" lỗi chính tả trong câu lệnh này EXEC sp_MSForEachTable "XÓA TỪ BẢNG?" Phiên bản chính xác phải là: EXEC sp_MSForEachTable "XÓA TỪ?"
Raghav

4
Nếu bạn đang sử dụng SSMS 2008 hoặc mới hơn, có thể bạn sẽ muốn thêm SET ROWCOUNT 0vào đầu tập lệnh của mình vì mặc định là giới hạn các hành động ở 500 hàng! Bạn sẽ nhận được các lỗi bực bội như tôi đã làm vì không phải tất cả dữ liệu sẽ thực sự bị xóa.
Sean Hanley

1
Điều này đã làm việc tuyệt vời. Trong trường hợp của tôi, tôi cũng phải thêm EXEC sp_msforeachtable "ALTER TABLE? Vô hiệu hóa TRIGGER all" và EXEC sp_msforeachtable "ALTER TABLE? Bật TRIGGER all" Trước và sau câu lệnh xóa.
RobC

2
Câu trả lời yêu thích của tôi. Nhưng tại sao bạn (tất cả, thậm chí cả những người bình luận) lại kèm theo các chuỗi SQL theo nghĩa đen?
bitoolean

57

Đây là vua cha của các kịch bản xóa cơ sở dữ liệu. Nó sẽ xóa tất cả các bảng và sắp xếp lại một cách chính xác:

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;

Thưởng thức, nhưng hãy cẩn thận!


2
Thật không may, lệnh trên không thành công nếu bạn đã tính toán các cột, vì sp_MSforeachtable rõ ràng có SET QUOTED_IDENTITY OFFtrong phần thân ( liên kết ). CẬP NHẬT: Cách khắc phục là thêm "SET QUOTED_IDENTIFIERS trên;" đến đầu mỗi câu phát sinh lỗi này (như đã đề cập ở đây )
Marchy

1
có vẻ như điều này không làm thay đổi danh tính của tôi
totooooo

48

Cách đơn giản nhất để làm điều này là

  1. mở SQL Management Studio
  2. điều hướng đến cơ sở dữ liệu của bạn
  3. Nhấp chuột phải và chọn Nhiệm vụ-> Tạo tập lệnh (ảnh 1)
  4. Trên màn hình "chọn đối tượng", chọn tùy chọn "chọn đối tượng cụ thể" và kiểm tra "bảng" (ảnh 2)
  5. trên màn hình tiếp theo, chọn "nâng cao" và sau đó thay đổi tùy chọn "Script DROP and CREATE" thành "Script DROP and CREATE" (ảnh 3)
  6. Chọn lưu tập lệnh vào cửa sổ soạn thảo mới hoặc tệp và chạy khi cần thiết.

điều này sẽ cung cấp cho bạn một tập lệnh bỏ và tạo lại tất cả các bảng của bạn mà không cần phải lo lắng về việc gỡ lỗi hoặc liệu bạn đã bao gồm mọi thứ chưa. Trong khi điều này thực hiện nhiều hơn chỉ là một cắt ngắn, kết quả là như nhau. Chỉ cần lưu ý rằng các khóa chính tăng tự động của bạn sẽ bắt đầu từ 0, trái ngược với các bảng bị cắt bớt sẽ ghi nhớ giá trị cuối cùng được gán. Bạn cũng có thể thực thi điều này từ mã nếu bạn không có quyền truy cập vào Studio quản lý trên môi trường PreProd hoặc Sản xuất.

1.

nhập mô tả hình ảnh ở đây

2.

nhập mô tả hình ảnh ở đây

3.

nhập mô tả hình ảnh ở đây


1
Thận trọng nếu bạn sử dụng điều này cho cơ sở dữ liệu với lược đồ rất phức tạp. Tôi đã thử nó trên một bản sao của DB sản xuất của chúng tôi và nó đã dọn sạch lược đồ, đòi hỏi phải triển khai lại toàn bộ.
Techrocket9

1
Bạn đã lên kịch bản tất cả những điều bạn muốn lưu giữ
Thuyền trưởng Kenpachi

12

Cắt bớt tất cả các bảng sẽ chỉ hoạt động nếu bạn không có bất kỳ mối quan hệ khóa ngoài nào giữa các bảng của mình, vì SQL Server sẽ không cho phép bạn cắt bớt một bảng có khóa ngoại.

Một cách khác để xác định điều này là xác định các bảng có khóa ngoại và xóa khỏi các bảng này trước, sau đó bạn có thể cắt các bảng mà không cần khóa ngoại sau đó.

Xem http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=65341http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72957 để biết thêm chi tiết.


1
Điểm tốt. Không nghĩ về điều đó. Tôi có thể vô hiệu hóa tất cả các ràng buộc trước và sau đó kích hoạt lại chúng sau khi dữ liệu đã được xóa.
Ray

7

Một tùy chọn khác mà tôi muốn sử dụng với MSSQL Server Deveploper hoặc Enterprise là tạo một ảnh chụp nhanh cơ sở dữ liệu ngay sau khi tạo lược đồ trống. Tại thời điểm đó, bạn có thể tiếp tục khôi phục cơ sở dữ liệu trở lại ảnh chụp nhanh.


Thật không may, bạn mất tất cả các chỉ mục FULLTEXT của mình mỗi lần
Chris KL

6

Đừng làm điều này! Thực sự, không phải là một ý tưởng tốt.

Nếu bạn biết bảng nào bạn muốn cắt bớt, hãy tạo một thủ tục được lưu trữ để cắt bớt chúng. Bạn có thể sửa chữa thứ tự để tránh các vấn đề quan trọng nước ngoài.

Nếu bạn thực sự muốn cắt bớt tất cả chúng (để bạn có thể tải BCP chẳng hạn), bạn sẽ nhanh chóng bỏ cơ sở dữ liệu và tạo một cơ sở dữ liệu mới từ đầu, điều này sẽ có thêm lợi ích mà bạn biết chính xác bạn đang ở đâu.


Cách tiếp cận thay thế tốt đẹp ở đây.
Sam

3
vấn đề với cách tiếp cận của bạn là việc bỏ các bảng và cơ sở dữ liệu sẽ dẫn đến việc mất tất cả các quyền được trao cho các thông tin đăng nhập và lược đồ khác nhau. Để tạo lại điều đó sẽ gây đau khổ cho cơ sở dữ liệu lớn với nhiều bảng.
Punit Vora

4

Nếu bạn muốn giữ dữ liệu trong một bảng cụ thể (ví dụ: bảng tra cứu tĩnh) trong khi xóa / cắt dữ liệu trong các bảng khác trong cùng một db, thì bạn cần một vòng lặp với các ngoại lệ trong đó. Đây là những gì tôi đang tìm kiếm khi tôi vấp phải câu hỏi này.

sp_MSForEachTable dường như có lỗi với tôi (nghĩa là hành vi không nhất quán với các câu lệnh IF) có lẽ là lý do tại sao nó không được ghi nhận bởi 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

Phần khó nhất của việc cắt bớt tất cả các bảng là loại bỏ và hỗ trợ lại các ràng buộc khóa ngoại.

Truy vấn sau đây tạo ra các câu lệnh thả và tạo cho từng ràng buộc liên quan đến từng tên bảng trong @myTempTable. Nếu bạn muốn tạo chúng cho tất cả các bảng, bạn có thể đơn giản sử dụng lược đồ thông tin để thu thập các tên bảng này thay thế.

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)

Sau đó tôi chỉ sao chép các câu lệnh để chạy - nhưng với một chút nỗ lực, bạn có thể sử dụng một con trỏ để chạy chúng một cách linh hoạt.


3

Sẽ dễ dàng hơn nhiều (và thậm chí có thể nhanh hơn) để kịch bản ra khỏi cơ sở dữ liệu của bạn, sau đó chỉ cần thả và tạo nó từ tập lệnh.


3

Tạo một cơ sở dữ liệu "mẫu" trống, sao lưu toàn bộ. Khi bạn cần làm mới, chỉ cần khôi phục bằng cách sử dụng VỚI REPLACE. Nhanh chóng, đơn giản, chống đạn. Và nếu một vài bảng ở đây hoặc ở đó cần một số dữ liệu cơ bản (ví dụ thông tin cấu hình hoặc chỉ thông tin cơ bản làm cho ứng dụng của bạn chạy) thì nó cũng xử lý điều đó.


2

Đây là một cách để làm điều đó ... có khả năng 10 cách khác tốt hơn / hiệu quả hơn, nhưng có vẻ như việc này được thực hiện rất không thường xuyên, vì vậy hãy đến đây ...

lấy một danh sách tablestừ sysobjects, sau đó lặp qua những cái đó bằng một con trỏ, gọi sp_execsql('truncate table ' + @table_name)cho mỗi cái iteration.


đã thêm bài đăng với sql chỉ làm điều này :) vì đây là những gì tôi đang tìm kiếm quá.
Chris Smith

1

Chạy phần nhận xét một lần, điền vào bảng _TruncateList với các bảng bạn muốn cắt bớt, sau đó chạy phần còn lại của tập lệnh. Bảng _ScriptLog sẽ cần được dọn sạch theo thời gian nếu bạn làm điều này nhiều.

Bạn có thể sửa đổi điều này nếu bạn muốn thực hiện tất cả các bảng, chỉ cần đặt tên CHỌN VÀO #TruncateList TỪ sys.tables. Tuy nhiên, bạn thường không muốn làm tất cả.

Ngoài ra, điều này sẽ ảnh hưởng đến tất cả các khóa ngoại trong cơ sở dữ liệu và bạn cũng có thể sửa đổi điều đó nếu nó quá mạnh cho ứng dụng của bạn. Nó không dành cho mục đích của tôi.

/*
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

Tôi không thấy lý do tại sao xóa dữ liệu sẽ tốt hơn một tập lệnh bỏ và tạo lại mỗi bảng.

Điều đó hoặc sao lưu DB trống của bạn và khôi phục lại DB cũ


2
Lý do là chi phí bỏ và tạo lại cơ sở dữ liệu trên các tệp, nhật ký, v.v ... rất chậm. Hãy suy nghĩ xóa sạch cơ sở dữ liệu 1.000 lần trong một lần chạy thử đơn vị đàng hoàng.
Chris KL

0

Trước khi cắt các bảng, bạn phải loại bỏ tất cả các khóa ngoại. Sử dụng tập lệnh này để tạo tập lệnh cuối cùng để thả và tạo lại tất cả các khóa ngoại trong cơ sở dữ liệu. Vui lòng đặt biến @action thành 'CREATE' hoặc 'DROP'.


0

chọn 'xóa khỏi' + TABLE_NAME từ THÔNG TIN_SCHema.TABLES trong đó TABLE_TYPE = 'BASE TABLE'

kết quả đến đâu

Sao chép và dán vào cửa sổ truy vấn và chạy lệnh


0

Hơi muộn một chút nhưng có thể giúp được ai đó. Tôi đã tạo một thủ tục đôi khi quay lại bằng cách sử dụng T-SQL:

  1. Lưu trữ tất cả các ràng buộc trong một bảng tạm thời
  2. Bỏ tất cả các ràng buộc
  3. Cắt bớt tất cả các bảng ngoại trừ một số bảng không cần cắt bớt
  4. Tái tạo tất cả các ràng buộc.

Tôi đã liệt kê nó trên blog của tôi ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.