Bir veritabanındaki tüm tabloları TSQL kullanarak nasıl kesersiniz?


204

Bir test döngüsü başında yeni verilerle yeniden yüklemek istediğim bir veritabanı için bir test ortamım var. Ben sadece sadece veri "yeniden" sadece tüm veritabanı yeniden inşa ilgilenmiyorum.

TSQL kullanarak tüm tablolardan tüm verileri kaldırmanın en iyi yolu nedir? Kullanılabilecek sistem saklı yordamları, görünümleri vb. Var mı? El ile oluşturmak ve her tablo için kesme tablo ifadeleri korumak istemiyorum-dinamik olmasını tercih ederim.

Yanıtlar:


188

SQL 2005 için,

EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'

2000 ve 2005/2008 için birkaç bağlantı daha ..


62
Yabancı anahtarları olan tabloları kesemezsiniz, bu nedenle yalnızca tablolar arasında yabancı anahtar kısıtlaması yoksa (veya devre dışı bırakılmışsa) çalışır.
marcj

1
kabul etti ... özellikle tabloları kesmeyi istediğinden, sorunu zaten yabancı anahtarlarla çözdüğünü düşündüm ..
Gulzar Nazim

@ gulzar- çeşit- FK'lerin nasıl ele alınacağı konusunda ayrı bir soru yayınladım ama cevabınız kendi değerlerine dayanıyor.
Ray

11
@Sam: Hayır, olmayacak! Tablolardaki veriler önemsizdir. Tabloya (engelli bile olsa) gönderme yapan yabancı bir anahtar kısıtlaması olduğu sürece onu kesemezsiniz.
TToni

3
'EXEC sp_MSForEachTable' DROP TABLE? ' İyi çalışıyor gibi :) (veritabanından tüm tabloları memnun)
kuncevic.dev

419

Yabancı anahtar ilişkileri olan tablolardan veri silmekle uğraşırken - temel olarak uygun şekilde tasarlanmış herhangi bir veritabanında olduğu gibi - tüm kısıtlamaları devre dışı bırakabilir, tüm verileri silebilir ve ardından kısıtlamaları yeniden etkinleştirebiliriz

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

Daha kısıtlamaları ve tetikleyicileri devre dışı bırakma hakkında burada

bazı tablolarda kimlik sütunları varsa, bunları yeniden boyutlandırmak isteyebiliriz

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

Not olduğu daha önce eklenen bir veri vardı reseed yeni tablo arasında farklılık, ve bir davranışı BOL :

DBCC CHECKIDENT ('tablo_adı', RESEED, newReseedValue)

Geçerli kimlik değeri newReseedValue olarak ayarlandı. Oluşturulduğundan beri tabloya hiç satır eklenmediyse, DBCC CHECKIDENT yürütüldükten sonra eklenen ilk satır kimlik olarak newReseedValue kullanır. Aksi takdirde, eklenen bir sonraki satır newReseedValue + 1 kullanır. NewReseedValue değeri kimlik sütunundaki maksimum değerden düşükse, tabloya sonraki başvurularda 2627 hata iletisi oluşturulur.

Sayesinde Robert kısıtlamaları devre dışı kesiğinin kullanmasına izin vermez gerçeği işaret için bırakılan ve daha sonra yeniden oluşturulması, kısıtlamalar olurdu


34
Kısıtlamaları devre dışı bırakmak, bir FOREIGN KEY kısıtlaması tarafından başvurulan tabloların kesilmesine izin VERMEZ. FK kısıtı kaldırılmalıdır. Bu konuda yanılıyorsam lütfen cevap verin, ancak onları düşürmekten kaçınmanın bir yolunu bulamadım.
Robert Claypool

1
Bu deyimde yalnızca bir yazım hatası "Tablo" anahtar sözcüğü bulunmamalıdır EXEC sp_MSForEachTable "TABLODAN SİL?" .Doğru sürüm şu şekilde olmalıdır: EXEC sp_MSForEachTable "BAŞLANGIÇ MI SİL?"
Raghav

4
2008 veya daha yeni SSMS kullanıyorsanız, büyük olasılıkla SET ROWCOUNT 0komut dosyanızın başına eklemek isteyeceksiniz, çünkü varsayılan ayar eylemleri 500 satıra sınırlamaktır! Benim yaptığım gibi sinir bozucu hatalar alacaksınız çünkü tüm veriler gerçekten silinmeyecek.
Sean Hanley

1
Bu harika çalıştı. Benim durumumda ayrıca EXEC sp_msforeachtable "ALTER TABLE? TRIGGER hepsini devre dışı bırak" ve EXEC sp_msforeachtable "ALTER TABLE? TRIGGER hepsini etkinleştir" ifadesini silme deyiminden önce ve sonra eklemek zorunda kaldım.
RobC

2
En sevdiğim cevap. Ama neden (hepsi, hatta yorumcular) gerçek SQL dizelerini çift tırnak içine aldınız?
bitoolean

57

İşte veritabanı silme komutlarının kral babası. Tüm tabloları temizler ve doğru şekilde yeniden boyutlandırır:

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;

Keyfini çıkarın, ama dikkatli olun!


2
Ne yazık ki yukarıdaki komut, hesaplanan sütunlarınız varsa başarısız olur, çünkü sp_MSforeachtable görünüşte SET QUOTED_IDENTITY OFFgövdesinde ( bağlantı ) bulunmaktadır. GÜNCELLEME: Düzeltme "SET QUOTED_IDENTIFIERS açık;" ( burada belirtildiği gibi ) bu hatayı ortaya çıkaran her bir ifadenin başına
2013

1
Görünüşe göre bu kimliğimi yeniden
yaratmadı

48

Bunu yapmanın en basit yolu

  1. SQL Management Studio'yu açın
  2. veri tabanına git
  3. Sağ tıklayın ve Görevler-> Komut Dosyaları Oluştur'u seçin (resim 1)
  4. "Nesneleri seç" ekranında, "belirli nesneleri seç" seçeneğini seçin ve "tabloları" kontrol edin (resim 2)
  5. sonraki ekranda "gelişmiş" i seçin ve ardından "Script DROP and CREATE" seçeneğini "Script DROP and CREATE" olarak değiştirin (resim 3)
  6. Komut dosyasını yeni bir düzenleyici penceresine veya bir dosyaya kaydetmeyi seçin ve gerekirse çalıştırın.

bu, hata ayıklama veya her şeyi ekleyip eklemediğiniz konusunda endişelenmenize gerek kalmadan tüm tablolarınızı bırakan ve yeniden yaratan bir komut dosyası verecektir. Bu sadece bir kesmeden daha fazlasını gerçekleştirse de, sonuçlar aynıdır. Otomatik artan birincil anahtarlarınızın, atanan son değeri hatırlayacak kesik tabloların aksine 0'da başlayacağını unutmayın. PreProd veya Üretim ortamlarınızdaki Yönetim stüdyosuna erişiminiz yoksa bunu koddan da yürütebilirsiniz.

1.

resim açıklamasını buraya girin

2.

resim açıklamasını buraya girin

3.

resim açıklamasını buraya girin


1
Bunu çok karmaşık bir şemaya sahip bir veritabanı için kullanıyorsanız dikkatli olun. Üretim DB'mizin dev bir kopyasında denedim ve şemayı çöpe attı ve toplam yeniden dağıtım gerektirdi.
Techrocket9

1
Korumak istediğiniz her şeyi senaryo etmelisiniz
Kaptan Kenpachi

13

Tüm tabloların kırpılması, yalnızca tablolarınız arasında herhangi bir yabancı anahtar ilişkiniz yoksa çalışır, çünkü SQL Server bir tabloyu yabancı anahtarla kısaltmanıza izin vermez.

Buna bir alternatif yabancı anahtarlı tabloları belirlemek ve ilk önce bunları silmek, daha sonra yabancı anahtar olmadan tabloları kesebilirsiniz.

Daha fazla bilgi için http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=65341 ve http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72957 adresine bakın.


1
İyi bir nokta. Bunu düşünmedim. Önce tüm kısıtlamaları devre dışı bırakabilir ve ardından veriler kaldırıldıktan sonra bunları yeniden etkinleştirebilirim.
Ray

7

MSSQL Server Deveploper veya Enterprise ile kullanmak istediğim alternatif bir seçenek, boş şemayı oluşturduktan hemen sonra veritabanının anlık görüntüsünü oluşturmaktır. Bu noktada veritabanını anlık görüntüye geri yüklemeye devam edebilirsiniz.


Ne yazık ki her defasında tüm FULLTEXT endekslerinizi kaybedersiniz
Chris KL

6

Bunu yapma! Gerçekten, iyi bir fikir değil.

Hangi tabloları kesmek istediğinizi biliyorsanız, onları kesen bir saklı yordam oluşturun. Yabancı anahtar sorunlarından kaçınmak için siparişi düzeltebilirsiniz.

Gerçekten hepsini kısaltmak istiyorsanız (örneğin BCP'yi yükleyebilirsiniz) veritabanını bırakmak ve sıfırdan yeni bir tane oluşturmak kadar hızlı olur, bu da tam olarak nerede olduğunuzu bildiğiniz ek yararı olur.


Burada güzel bir alternatif yaklaşım.
Sam

3
yaklaşımınızdaki sorun, tabloları ve veritabanını bırakmanın farklı giriş ve şemalara verilen tüm izinlerin kaybedilmesine yol açmasıdır. Yeniden oluşturmak için çok tablo içeren büyük veritabanları için acı verici olacaktır.
Punit Vora

4

Verileri aynı db içindeki diğer tablolardaki verileri silerken / keserken belirli bir tabloda (yani statik arama tablosu) tutmak istiyorsanız, istisnaları olan bir döngüye ihtiyacınız vardır. Bu soruyu tökezlediğimde aradığım şey buydu.

sp_MSForEachTable bana bir hata gibi görünüyor (yani IF deyimleriyle tutarsız davranış), bu yüzden muhtemelen MS tarafından belgelenmemiştir.

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

Tüm tabloları kısaltmanın en zor kısmı, yabancı anahtar kısıtlamalarını kaldırmak ve yeniden eklemek.

Aşağıdaki sorgu @ myTempTable'daki her tablo adıyla ilgili her kısıtlama için drop & create deyimlerini oluşturur. Bunları tüm tablolar için oluşturmak isterseniz, bu tablo adlarını toplamak için bilgi şemasını kullanabilirsiniz.

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)

Sonra sadece çalıştırmak için ifadeleri kopyalayın - ama biraz çaba ile onları dinamik olarak çalıştırmak için bir imleç kullanabilirsiniz.


3

Veritabanınızı komut dosyası haline getirmek çok daha kolay (ve hatta daha hızlı), sonra sadece komut dosyasından bırakın ve oluşturun.


3

Boş bir "şablon" veritabanı oluşturun, tam bir yedek alın. Yenilemeniz gerektiğinde, İLE DEĞİŞTİR seçeneğini kullanarak geri yükleyin. Hızlı, basit, kurşun geçirmez. Ve burada birkaç tablo varsa veya bazı temel verilere ihtiyaç duyarsanız (örn. Yapılandırma bilgileri veya yalnızca uygulamanızı çalıştıran temel bilgiler) bunu da ele alır.


2

Bunu yapmanın bir yolu ... muhtemelen daha iyi / daha verimli olan 10 tane daha var, ama bunun çok seyrek yapıldığı anlaşılıyor, işte burada ...

' tablesdan bir liste alın sysobjects, sonra imleci olanların üzerine gelin sp_execsql('truncate table ' + @table_name)ve her birini arayın iteration.


sadece bu :) çünkü bu ben de aradığını oldu sql ile yazı eklendi.
Chris Smith

1

Yorum yapılan bölümü bir kez çalıştırın, _TruncateList tablosunu kesilmesini istediğiniz tablolarla doldurun, ardından komut dosyasının geri kalanını çalıştırın. Bunu çok yaparsanız, _ScriptLog tablosunun zaman içinde temizlenmesi gerekir.

Tüm tabloları yapmak istiyorsanız bunu değiştirebilirsiniz, sadece SELECT name INTO #TruncateList FROM sys.tables komutunu girin. Ancak, genellikle hepsini yapmak istemezsiniz.

Ayrıca, bu, veritabanındaki tüm yabancı anahtarları etkiler ve uygulamanız için çok kör kuvvet varsa, bunu da değiştirebilirsiniz. Benim amacım için değil.

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

Neden veri temizleme neden bir tablo bırak ve yeniden her tablo oluşturmak için daha iyi olacağını görmüyorum.

Bu veya boş DB'nizi yedekleyin ve eski DB'nizi geri yükleyin


2
Bunun nedeni, diskteki dosyaları, günlükleri vb. Veritabanını bırakma ve yeniden oluşturma yükünün çok yavaş olmasıdır. İyi bir birim test çalışması sırasında veritabanını 1.000 kez silmeyi düşünün.
Chris KL

0

Masaları kesmeden önce tüm yabancı anahtarları çıkarmanız gerekir. Veritabanındaki tüm yabancı anahtarları bırakmak ve yeniden oluşturmak için son komut dosyaları oluşturmak için bu komut dosyasını kullanın . Lütfen @action değişkenini 'CREATE' veya 'DROP' olarak ayarlayın.


0

TABLE_TYPE = 'BASE TABLO' dan BİLGİ_SCHEMA.TABLES'dan 'sil' + TABLE_NAME 'i seçin

sonuç gelir.

Sorgu penceresine kopyalayıp yapıştırın ve komutu çalıştırın


0

Biraz geç oldu ama birine yardım edebilir. Bazen T-SQL kullanarak aşağıdakileri yapan bir yordam oluşturdum:

  1. Tüm kısıtlamaları Geçici bir tabloda depolama
  2. Tüm Kısıtlamaları Bırak
  3. Kesme gerektirmeyen bazı tablolar dışında tüm tabloları kırp
  4. Tüm Kısıtlamaları yeniden oluşturun.

Burada blogumda listeledim

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.