Yabancı anahtar kısıtlamaları T-SQL kullanılarak geçici olarak nasıl devre dışı bırakılabilir?


824

SQL Server'da devre dışı bırakma ve etkinleştirme yabancı anahtar kısıtlamaları destekleniyor mu? Yoksa benim tek seçeneğim kısıtlamalar için mi, dropsonra yenidencreate mi?


128
"Neden" diye soran millet için ben bunu yapmak istiyorum: Ben korumak ve verilerin yüklenme sırasını belirtmek gerek kalmadan birden çok tablodan test verileri kaldırmak ve yüklemek mümkün olduğu bir test ortamı içindir. Veri bütünlüğü bu senaryo için o kadar önemli değildir.
Ray

8
Not - tabloyu TRUNCATE yapmak istiyorsanız, kısıtlamaları gerçekten düşürmeniz gerekir.
OutstandingBill

@OutstandingBill Görünüşe göre, bu TRUNCATE için çalışıyor .
jpaugh

1
Üretim ortamında herkesin bunu sorgulaması tuhaf görünüyor . Çok yaygın bir kullanım durumu, toplu kesici uçlar içindir. Kendi kendine başvuru yapan bir tablonuz varsa, toplu satırın üst satırını her zaman alt öğeden önce eklenecek şekilde sıralamak bazen zor olabilir, böylece kısıtlamayı devre dışı bırakırsınız, toplu ekleme, kısıtlamayı etkinleştirirsiniz.
Auspex

Yanıtlar:


1126

Veritabanındaki tüm kısıtlamaları devre dışı bırakmak istiyorsanız şu kodu çalıştırın:

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

Onları tekrar açmak için şunu çalıştırın: (baskı elbette isteğe bağlıdır ve sadece tabloları listeler)

-- enable all constraints
exec sp_MSforeachtable @command1="print '?'", @command2="ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"

Veriyi bir veritabanından diğerine doldururken faydalı buluyorum. Kısıtlamaları bırakmaktan daha iyi bir yaklaşımdır. Bahsettiğiniz gibi, veritabanındaki tüm verileri bırakarak ve yeniden doldurarak kullanışlı olur (örneğin test ortamında).

Tüm verileri siliyorsanız, bu çözümü faydalı bulabilirsiniz .

Ayrıca bazen tüm tetikleyicileri de devre dışı bırakmak yararlıdır, tam çözümü burada görebilirsiniz .


9
"ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"Orada sadece bir tane "CHECK" olmalı mı?
CrazyPyro

27
@CrazyPyro - hayır her ikisi de gerek
kristof

32
@CrazyPyro: her ikisine de gerçekten ihtiyaç vardır, bunun nedeni ilk CHECK'in WITH ile ve ikinci CHECK ile CONSTRAINT'e ait olmasıdır (kısıtlama türüdür). İlk CHECK, kısıtlamayı etkinleştirirken verilerinizin tutarlılığını kontrol etmesini sağlar. Eğer istemiyorsanız, NOCHECK İLE yazabilirsiniz. Sorgularınızla oynayabileceğiniz bazı şeyler olduğu sürece, gerçek verileri umursamadığınız belirli test durumlarında yararlı olabilir.
Valentino Vranken

8
Bu sonucu ikinci komutta almam kötü mü? "ALTER TABLE ifadesi YABANCI ANAHTAR kısıtlaması ile çelişti ..."
Şeytan'ın Avukatı

34
Kısıtlamalar devre dışı bırakılsa bile, TRUNCATE TABLE'ın çalışmadığını belirtmek gerekir. Bunun için kısıtlamaları bırakmanız gerekecek. Aksi takdirde, SİL'i kullanın, ancak farkı göz önünde bulundurun: mssqltips.com/sqlservertip/1080/…
James McCormack

404

http://www.sqljunkies.com/WebLog/roman/archive/2005/01/30/7037.aspx

-- Disable all table constraints

ALTER TABLE MyTable NOCHECK CONSTRAINT ALL

-- Enable all table constraints

ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT ALL

-- Disable single constraint

ALTER TABLE MyTable NOCHECK CONSTRAINT MyConstraint

-- Enable single constraint

ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint

29
iyi bir bulgu, ancak yabancı anahtar kısıtlamalarını kaldırmadan tabloyu kesemeyeceğinizi unutmayın
Steven A. Lowe

1
ayrıca, kısıtlamaları tekrar açıp veri bütünlüğü kontrolü yaptığınızda, verilerinizin başarısız olabileceğini ve başarısız verilerin uzun bir dizenin sonunda olması durumunda böyle bir sorunu kabus olabileceğini de bilmeniz gerekir. bağlantılı kısıtlamalar.
Jimoc

1
Kısıtlamaları tekrar açarken de ikinci bir kontrol yapmanız gerekir. Aksi takdirde, olduğu gibi, kodunuz kısıtlamayı yalnızca bir kez kontrol eder, açmaz.
ps2goat

3
evet, 2012 için "çekle kontrol" gerekli. Düzenleme reddedildi mi? MS Link
crokusek

1
Burada kısıtlamaları yeniden etkinleştirmek için kullanılan ifadelerde WITH CHECK deyimleri yoktur. Bu oldukça büyük bir kusur. Ayrıntılar için cevabıma bakın - stackoverflow.com/a/35427150/81595 .
Scott Munro

37

Kısıtlamayı devre dışı bırakmak için NOCHECKALTER kullanarak tablonuz olur

ALTER TABLE [TABLE_NAME] NOCHECK CONSTRAINT [ALL|CONSTRAINT_NAME]

Double CHECK kullanmanız için :

ALTER TABLE [TABLE_NAME] WITH CHECK CHECK CONSTRAINT [ALL|CONSTRAINT_NAME]
  • Etkinleştirirken çift CHECK CHECK'e dikkat edin .
  • ALL, tablodaki tüm kısıtlamalar için anlamına gelir.

Tamamlandığında, durumu kontrol etmeniz gerekiyorsa, kısıtlama durumunu listelemek için bu komut dosyasını kullanın. Çok yardımcı olacak:

    SELECT (CASE 
        WHEN OBJECTPROPERTY(CONSTID, 'CNSTISDISABLED') = 0 THEN 'ENABLED'
        ELSE 'DISABLED'
        END) AS STATUS,
        OBJECT_NAME(CONSTID) AS CONSTRAINT_NAME,
        OBJECT_NAME(FKEYID) AS TABLE_NAME,
        COL_NAME(FKEYID, FKEY) AS COLUMN_NAME,
        OBJECT_NAME(RKEYID) AS REFERENCED_TABLE_NAME,
        COL_NAME(RKEYID, RKEY) AS REFERENCED_COLUMN_NAME
   FROM SYSFOREIGNKEYS
ORDER BY TABLE_NAME, CONSTRAINT_NAME,REFERENCED_TABLE_NAME, KEYNO 

Değil görüntülemek için Birincil anahtarlar ? İçin yabancı anahtarları SYSFOREIGNKEYS Sistemi Görünümü sys.sysforeignkeys msdn.microsoft.com/en-us/library/ms177604.aspx
Kiquenet

ekleme için birincil anahtarı devre dışı bırakmaya çalışıyorsanız, yalnızca birincil anahtarı kontrol etmek istiyorsanız (SET IDENTITY_INSERT) kullanmanızı öneririm, sys.indexes.is_primary_key ile sys.key_constraints'i deneyebilirsiniz
Diego Mendes

29

En iyi seçeneğiniz DROP ve CREATE FOR yabancı anahtar kısıtlamalarıdır.

Bu yazıda benim için "olduğu gibi" çalışacak örnekler bulamadım, yabancı anahtarlar farklı şemalara başvurursa işe yaramaz, diğeri yabancı anahtar birden çok sütuna başvurursa işe yaramaz. Bu komut dosyası, yabancı anahtar başına birden çok şemayı ve birden çok sütunu dikkate alır.

"ADD CONSTRAINT" ifadeleri üreten komut dosyası, birden çok sütun için virgülle ayıracaktır ( DROP ifadelerini çalıştırmadan önce bu çıktıyı kaydettiğinizden emin olun ):

PRINT N'-- CREATE FOREIGN KEY CONSTRAINTS --';

SET NOCOUNT ON;
SELECT '
PRINT N''Creating '+ const.const_name +'...''
GO
ALTER TABLE ' + const.parent_obj + '
    ADD CONSTRAINT ' + const.const_name + ' FOREIGN KEY (
            ' + const.parent_col_csv + '
            ) REFERENCES ' + const.ref_obj + '(' + const.ref_col_csv + ')
GO'
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

"DROP CONSTRAINT" ifadelerini üreten komut dosyası:

PRINT N'-- DROP FOREIGN KEY CONSTRAINTS --';

SET NOCOUNT ON;

SELECT '
PRINT N''Dropping ' + fk.NAME + '...''
GO
ALTER TABLE [' + sch.NAME + '].[' + OBJECT_NAME(fk.parent_object_id) + ']' + ' DROP  CONSTRAINT ' + '[' + fk.NAME + ']
GO'
FROM sys.foreign_keys AS fk
INNER JOIN sys.schemas AS sch ON sch.schema_id = fk.schema_id
ORDER BY fk.NAME

5
Kısıtlamaları devre dışı bırakıp yeniden etkinleştirmekten neden daha iyi olduğunu açıklayabilir misiniz?
Mahmoodvcs

Güzel senaryo. Benzer ama alternatif bir yaklaşım için bkz. Mssqltips.com/sqlservertip/3347/…
Matt Browne

11

SQL-92 standardı, bir sabitin bir işlem kapsamında ertelenebilmesi için (örtük olarak veya açıkça) DEFERRABLE olarak bildirilmesine izin verir. Ne yazık ki, SQL Server hala bu SQL-92 işlevselliğini eksik.

Benim için NOCHECK olarak bir kısıtlamayı değiştirmek, veritabanı yapısını anında bırakma kısıtlamalarında değiştirmeye kesinlikle benzer - ve kaçınılması gereken bir şey (örneğin, kullanıcılar daha fazla ayrıcalık gerektirir).


11
   --Drop and Recreate Foreign Key Constraints

SET NOCOUNT ON

DECLARE @table TABLE(
   RowId INT PRIMARY KEY IDENTITY(1, 1),
   ForeignKeyConstraintName NVARCHAR(200),
   ForeignKeyConstraintTableSchema NVARCHAR(200),
   ForeignKeyConstraintTableName NVARCHAR(200),
   ForeignKeyConstraintColumnName NVARCHAR(200),
   PrimaryKeyConstraintName NVARCHAR(200),
   PrimaryKeyConstraintTableSchema NVARCHAR(200),
   PrimaryKeyConstraintTableName NVARCHAR(200),
   PrimaryKeyConstraintColumnName NVARCHAR(200)    
)

INSERT INTO @table(ForeignKeyConstraintName, ForeignKeyConstraintTableSchema, ForeignKeyConstraintTableName, ForeignKeyConstraintColumnName)
SELECT 
   U.CONSTRAINT_NAME, 
   U.TABLE_SCHEMA, 
   U.TABLE_NAME, 
   U.COLUMN_NAME 
FROM 
   INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
      INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
         ON U.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE
   C.CONSTRAINT_TYPE = 'FOREIGN KEY'

UPDATE @table SET
   PrimaryKeyConstraintName = UNIQUE_CONSTRAINT_NAME
FROM 
   @table T
      INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R
         ON T.ForeignKeyConstraintName = R.CONSTRAINT_NAME

UPDATE @table SET
   PrimaryKeyConstraintTableSchema  = TABLE_SCHEMA,
   PrimaryKeyConstraintTableName  = TABLE_NAME
FROM @table T
   INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
      ON T.PrimaryKeyConstraintName = C.CONSTRAINT_NAME

UPDATE @table SET
   PrimaryKeyConstraintColumnName = COLUMN_NAME
FROM @table T
   INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
      ON T.PrimaryKeyConstraintName = U.CONSTRAINT_NAME

--SELECT * FROM @table

--DROP CONSTRAINT:
SELECT
   '
   ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
   DROP CONSTRAINT ' + ForeignKeyConstraintName + '

   GO'
FROM
   @table

--ADD CONSTRAINT:
SELECT
   '
   ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
   ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ')

   GO'
FROM
   @table

GO

Sana katılıyorum Hamlin. Verileri SSIS kullanarak aktarırken veya verileri çoğaltmak istediğinizde, yabancı anahtar kısıtlamalarını geçici olarak devre dışı bırakmak veya bırakmak ve ardından bunları yeniden etkinleştirmek veya yeniden oluşturmak oldukça gerekli görünmektedir. Bu durumlarda, kaynak bütünlüğünde zaten korunduğu için başvuru bütünlüğü bir sorun değildir. Bu nedenle, bu konuda emin olabilirsiniz.


Bu komut dosyası "ALTER" komutlarımı oluşturmak için harika, ancak bunları bir SP'de çalıştırmak / çalıştırmak için nasıl edinebilirim?
BlueChippy

1
Yabancı anahtarlardan herhangi biri çok
sütunluysa

Bu, son derece uzun tablo / anahtar adları için de tüm karakterleri üretmedi.
Joshua Drake

11
SET NOCOUNT ON

DECLARE @table TABLE(
   RowId INT PRIMARY KEY IDENTITY(1, 1),
   ForeignKeyConstraintName NVARCHAR(200),
   ForeignKeyConstraintTableSchema NVARCHAR(200),
   ForeignKeyConstraintTableName NVARCHAR(200),
   ForeignKeyConstraintColumnName NVARCHAR(200),
   PrimaryKeyConstraintName NVARCHAR(200),
   PrimaryKeyConstraintTableSchema NVARCHAR(200),
   PrimaryKeyConstraintTableName NVARCHAR(200),
   PrimaryKeyConstraintColumnName NVARCHAR(200),
   UpdateRule NVARCHAR(100),
   DeleteRule NVARCHAR(100)   
)

INSERT INTO @table(ForeignKeyConstraintName, ForeignKeyConstraintTableSchema, ForeignKeyConstraintTableName, ForeignKeyConstraintColumnName)
SELECT 
   U.CONSTRAINT_NAME, 
   U.TABLE_SCHEMA, 
   U.TABLE_NAME, 
   U.COLUMN_NAME
FROM 
   INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
      INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
         ON U.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE
   C.CONSTRAINT_TYPE = 'FOREIGN KEY'

UPDATE @table SET
   T.PrimaryKeyConstraintName = R.UNIQUE_CONSTRAINT_NAME,
   T.UpdateRule = R.UPDATE_RULE,
   T.DeleteRule = R.DELETE_RULE
FROM 
   @table T
      INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R
         ON T.ForeignKeyConstraintName = R.CONSTRAINT_NAME

UPDATE @table SET
   PrimaryKeyConstraintTableSchema  = TABLE_SCHEMA,
   PrimaryKeyConstraintTableName  = TABLE_NAME
FROM @table T
   INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
      ON T.PrimaryKeyConstraintName = C.CONSTRAINT_NAME

UPDATE @table SET
   PrimaryKeyConstraintColumnName = COLUMN_NAME
FROM @table T
   INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
      ON T.PrimaryKeyConstraintName = U.CONSTRAINT_NAME

--SELECT * FROM @table

SELECT '
BEGIN TRANSACTION
BEGIN TRY'

--DROP CONSTRAINT:
SELECT
   '
 ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
 DROP CONSTRAINT ' + ForeignKeyConstraintName + '
   '
FROM
   @table

SELECT '
END TRY

BEGIN CATCH
   ROLLBACK TRANSACTION
   RAISERROR(''Operation failed.'', 16, 1)
END CATCH

IF(@@TRANCOUNT != 0)
BEGIN
   COMMIT TRANSACTION
   RAISERROR(''Operation completed successfully.'', 10, 1)
END
'

--ADD CONSTRAINT:
SELECT '
BEGIN TRANSACTION
BEGIN TRY'

SELECT
   '
   ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] 
   ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ') ON UPDATE ' + UpdateRule + ' ON DELETE ' + DeleteRule + '
   '
FROM
   @table

SELECT '
END TRY

BEGIN CATCH
   ROLLBACK TRANSACTION
   RAISERROR(''Operation failed.'', 16, 1)
END CATCH

IF(@@TRANCOUNT != 0)
BEGIN
   COMMIT TRANSACTION
   RAISERROR(''Operation completed successfully.'', 10, 1)
END'

GO

10

WITH CHECK CHECK neredeyse kesinlikle gerekli!

Bu nokta bazı cevaplarda ve yorumlarda dile getirildi, ancak tekrar çağırmanın yeterince önemli olduğunu düşünüyorum.

Aşağıdaki komutu (no WITH CHECK) kullanarak bir kısıtlamanın yeniden etkinleştirilmesinin bazı ciddi dezavantajları olacaktır .

ALTER TABLE MyTable CHECK CONSTRAINT MyConstraint;

ÇEK İLE | KOLYE İLE

Tablodaki verilerin yeni eklenen veya yeniden etkinleştirilen bir FOREIGN KEY veya CHECK kısıtlamasına göre doğrulanıp onaylanmadığını belirtir. Belirtilmezse, yeni kısıtlamalar için WITH CHECK, yeniden etkinleştirilen kısıtlamalar için WITH NOCHECK varsayılır.

Var olan verilere karşı yeni CHECK veya FOREIGN KEY kısıtlamalarını doğrulamak istemiyorsanız WITH NOCHECK kullanın. Nadir durumlar dışında bunu yapmanızı önermiyoruz. Yeni kısıtlama, daha sonraki tüm veri güncellemelerinde değerlendirilecektir. Kısıtlama eklendiğinde WITH NOCHECK tarafından bastırılan herhangi bir kısıtlama ihlali, satırları kısıtlamaya uymayan verilerle güncelleştirmeleri durumunda gelecekteki güncelleştirmelerin başarısız olmasına neden olabilir.

Sorgu iyileştirici, NOCHECK ile tanımlanan kısıtlamaları dikkate almaz. Bu tür kısıtlamalar, CHECK CHECK CONSTRAINT ALL İLE ALTER TABLE tablosu kullanılarak yeniden etkinleştirilene kadar yok sayılır.

Not: WITH NOCHECK, kısıtlamaları yeniden etkinleştirmek için varsayılan ayardır. Nedenini merak etmeliyim ...

  1. Bu komutun yürütülmesi sırasında tablodaki hiçbir veri değerlendirilmez - başarılı tamamlama, tablodaki verilerin kısıtlamaya göre geçerli olduğunun garantisi değildir.
  2. Geçersiz kayıtların bir sonraki güncellemesi sırasında, kısıtlama değerlendirilir ve başarısız olur; bu, yapılan güncellemeyle ilgisi olmayan hatalara yol açar.
  3. Verilerin geçerli olduğundan emin olmak için kısıtlamaya dayanan uygulama mantığı başarısız olabilir.
  4. Sorgu iyileştirici, bu şekilde etkinleştirilen herhangi bir kısıtlamayı kullanmayacaktır.

Sys.foreign_keys sistem görünümü sorunu içine bazı görüş açısı sağlar. Hem bir hem de is_disabledbir is_not_trustedsütunu olduğunu unutmayın. is_disabledgelecekteki veri işleme işlemlerinin kısıtlamaya göre doğrulanıp onaylanmayacağını belirtir. is_not_trustedgeçerli olarak tablodaki tüm verilerin kısıtlamaya göre doğrulanıp onaylanmadığını belirtir.

ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint;

Kısıtlamalarınıza güvenilecek mi? Bulmak...

SELECT * FROM sys.foreign_keys WHERE is_not_trusted = 1;

9

İlk gönderi :)

OP için, büyük silmelerde büyük veri ve işlem günlüğü balon sorunları ile ilgili sorunlar olmadıkça, kristof'un çözümü işe yarayacaktır. Ayrıca, yedeklenecek tlog depolama ile bile, tlog'a yazma silindiği için, işlem yüz milyonlarca satıra sahip tablolar için ÇOK uzun sürebilir.

Büyük üretim veritabanlarımızdan birinin büyük kopyalarını sık sık kesip yeniden yüklemek için bir dizi imleç kullanıyorum. Çözüm mühendisliği, çoklu şemalar, çoklu yabancı anahtar sütunları ve hepsinden önemlisi SSIS'te kullanım için kullanılabilir.

DROP, CREATE ve CHECK FK komut dosyalarını barındırmak için üç aşamalı tablonun (gerçek tablolar) oluşturulmasını, bu komut dosyalarının oluşturulmasını ve tablolara eklenmesini ve ardından tabloların üzerine döngü yapıp yürütülmesini içerir. Ekli komut dosyası dört bölümden oluşur: 1.) üç aşamalı (gerçek) tablodaki komut dosyalarının oluşturulması ve saklanması, 2.) bırakılan FK komut dosyalarının bir imleç aracılığıyla tek tek yürütülmesi, 3.) sp_MSforeachtable kullanarak tüm Veritabanında üç aşama tablomuz dışında tablolar ve 4.) ETL SSIS paketinizin sonunda FK oluşturma ve FK komut dosyalarını kontrol etme.

Komut dosyası oluşturma bölümünü SSIS'de SQL Yürüt görevinde çalıştırın. İkinci bir Execute SQL görevinde "Drop FK Scripts yürüt" bölümünü çalıştırın. Kesme komut dosyasını üçüncü bir Execute SQL görevine koyun, ardından CREATE ve CHECK komut dosyalarını kontrol akışınızın sonunda bir son Execute SQL görevine (veya istenirse iki) eklemeden önce yapmanız gereken diğer ETL işlemlerini gerçekleştirin.

Yabancı anahtarların yeniden uygulanması başarısız olduğunda komut dosyalarının gerçek tablolarda saklanması, sync_CreateFK'den * seçip, sorgu pencerenize kopyala / yapıştır, her seferinde bir tane çalıştırıp veri sorunlarını giderebildiğinizde çok değerli olduğu kanıtlanmıştır. başarısız olan / hala tekrar başvuru yapamayanları bulun.

Bunu yapmadan önce tüm yabancı anahtarları / denetimleri yeniden uyguladığınızdan emin olmadan komut dosyasını yeniden çalıştırmayın veya büyük olasılıkla bazı oluşturma işlemlerini kaybedersiniz ve hazırlama tablolarımız düştükçe fk komut dosyasını kontrol edersiniz. yürütmek için komut dosyaları oluşturulmadan önce yeniden.

----------------------------------------------------------------------------
1)
/*
Author:         Denmach
DateCreated:    2014-04-23
Purpose:        Generates SQL statements to DROP, ADD, and CHECK existing constraints for a 
                database.  Stores scripts in tables on target database for execution.  Executes
                those stored scripts via independent cursors. 
DateModified:
ModifiedBy
Comments:       This will eliminate deletes and the T-log ballooning associated with it.
*/

DECLARE @schema_name SYSNAME; 
DECLARE @table_name SYSNAME; 
DECLARE @constraint_name SYSNAME; 
DECLARE @constraint_object_id INT; 
DECLARE @referenced_object_name SYSNAME; 
DECLARE @is_disabled BIT; 
DECLARE @is_not_for_replication BIT; 
DECLARE @is_not_trusted BIT; 
DECLARE @delete_referential_action TINYINT; 
DECLARE @update_referential_action TINYINT; 
DECLARE @tsql NVARCHAR(4000); 
DECLARE @tsql2 NVARCHAR(4000); 
DECLARE @fkCol SYSNAME; 
DECLARE @pkCol SYSNAME; 
DECLARE @col1 BIT; 
DECLARE @action CHAR(6);  
DECLARE @referenced_schema_name SYSNAME;



--------------------------------Generate scripts to drop all foreign keys in a database --------------------------------

IF OBJECT_ID('dbo.sync_dropFK') IS NOT NULL
DROP TABLE sync_dropFK

CREATE TABLE sync_dropFK
    (
    ID INT IDENTITY (1,1) NOT NULL
    , Script NVARCHAR(4000)
    )

DECLARE FKcursor CURSOR FOR

    SELECT 
        OBJECT_SCHEMA_NAME(parent_object_id)
        , OBJECT_NAME(parent_object_id)
        , name
    FROM 
        sys.foreign_keys WITH (NOLOCK)
    ORDER BY 
        1,2;

OPEN FKcursor;

FETCH NEXT FROM FKcursor INTO 
    @schema_name
    , @table_name
    , @constraint_name

WHILE @@FETCH_STATUS = 0

BEGIN
        SET @tsql = 'ALTER TABLE '
                + QUOTENAME(@schema_name) 
                + '.' 
                + QUOTENAME(@table_name)
                + ' DROP CONSTRAINT ' 
                + QUOTENAME(@constraint_name) 
                + ';';
    --PRINT @tsql;
    INSERT sync_dropFK  (
                        Script
                        )
                        VALUES (
                                @tsql
                                )   

    FETCH NEXT FROM FKcursor INTO 
    @schema_name
    , @table_name
    , @constraint_name
    ;

END;

CLOSE FKcursor;

DEALLOCATE FKcursor;


---------------Generate scripts to create all existing foreign keys in a database --------------------------------
----------------------------------------------------------------------------------------------------------
IF OBJECT_ID('dbo.sync_createFK') IS NOT NULL
DROP TABLE sync_createFK

CREATE TABLE sync_createFK
    (
    ID INT IDENTITY (1,1) NOT NULL
    , Script NVARCHAR(4000)
    )

IF OBJECT_ID('dbo.sync_createCHECK') IS NOT NULL
DROP TABLE sync_createCHECK

CREATE TABLE sync_createCHECK
    (
    ID INT IDENTITY (1,1) NOT NULL
    , Script NVARCHAR(4000)
    )   

DECLARE FKcursor CURSOR FOR

     SELECT 
        OBJECT_SCHEMA_NAME(parent_object_id)
        , OBJECT_NAME(parent_object_id)
        , name
        , OBJECT_NAME(referenced_object_id)
        , OBJECT_ID
        , is_disabled
        , is_not_for_replication
        , is_not_trusted
        , delete_referential_action
        , update_referential_action
        , OBJECT_SCHEMA_NAME(referenced_object_id)

    FROM 
        sys.foreign_keys WITH (NOLOCK)

    ORDER BY 
        1,2;

OPEN FKcursor;

FETCH NEXT FROM FKcursor INTO 
    @schema_name
    , @table_name
    , @constraint_name
    , @referenced_object_name
    , @constraint_object_id
    , @is_disabled
    , @is_not_for_replication
    , @is_not_trusted
    , @delete_referential_action
    , @update_referential_action
    , @referenced_schema_name;

WHILE @@FETCH_STATUS = 0

BEGIN

        BEGIN
            SET @tsql = 'ALTER TABLE '
                        + QUOTENAME(@schema_name) 
                        + '.' 
                        + QUOTENAME(@table_name)
                        +   CASE 
                                @is_not_trusted
                                WHEN 0 THEN ' WITH CHECK '
                                ELSE ' WITH NOCHECK '
                            END
                        + ' ADD CONSTRAINT ' 
                        + QUOTENAME(@constraint_name)
                        + ' FOREIGN KEY (';

        SET @tsql2 = '';

        DECLARE ColumnCursor CURSOR FOR 

            SELECT 
                COL_NAME(fk.parent_object_id
                , fkc.parent_column_id)
                , COL_NAME(fk.referenced_object_id
                , fkc.referenced_column_id)

            FROM 
                sys.foreign_keys fk WITH (NOLOCK)
                INNER JOIN sys.foreign_key_columns fkc WITH (NOLOCK) ON fk.[object_id] = fkc.constraint_object_id

            WHERE 
                fkc.constraint_object_id = @constraint_object_id

            ORDER BY 
                fkc.constraint_column_id;

        OPEN ColumnCursor;

        SET @col1 = 1;

        FETCH NEXT FROM ColumnCursor INTO @fkCol, @pkCol;

        WHILE @@FETCH_STATUS = 0

        BEGIN
            IF (@col1 = 1)
                SET @col1 = 0;
            ELSE
            BEGIN
                SET @tsql = @tsql + ',';
                SET @tsql2 = @tsql2 + ',';
            END;

            SET @tsql = @tsql + QUOTENAME(@fkCol);
            SET @tsql2 = @tsql2 + QUOTENAME(@pkCol);
            --PRINT '@tsql = ' + @tsql 
            --PRINT '@tsql2 = ' + @tsql2
            FETCH NEXT FROM ColumnCursor INTO @fkCol, @pkCol;
            --PRINT 'FK Column ' + @fkCol
            --PRINT 'PK Column ' + @pkCol 
        END;

        CLOSE ColumnCursor;
        DEALLOCATE ColumnCursor;

        SET @tsql = @tsql + ' ) REFERENCES ' 
                    + QUOTENAME(@referenced_schema_name) 
                    + '.' 
                    + QUOTENAME(@referenced_object_name)
                    + ' (' 
                    + @tsql2 + ')';

        SET @tsql = @tsql
                    + ' ON UPDATE ' 
                    + 
                        CASE @update_referential_action
                            WHEN 0 THEN 'NO ACTION '
                            WHEN 1 THEN 'CASCADE '
                            WHEN 2 THEN 'SET NULL '
                                ELSE 'SET DEFAULT '
                        END

                    + ' ON DELETE ' 
                    + 
                        CASE @delete_referential_action
                            WHEN 0 THEN 'NO ACTION '
                            WHEN 1 THEN 'CASCADE '
                            WHEN 2 THEN 'SET NULL '
                                ELSE 'SET DEFAULT '
                        END

                    + 
                    CASE @is_not_for_replication
                        WHEN 1 THEN ' NOT FOR REPLICATION '
                            ELSE ''
                    END
                    + ';';

        END;

    --  PRINT @tsql
        INSERT sync_createFK    
                        (
                        Script
                        )
                        VALUES (
                                @tsql
                                )

-------------------Generate CHECK CONSTRAINT scripts for a database ------------------------------
----------------------------------------------------------------------------------------------------------

        BEGIN

        SET @tsql = 'ALTER TABLE '
                    + QUOTENAME(@schema_name) 
                    + '.' 
                    + QUOTENAME(@table_name)
                    + 
                        CASE @is_disabled
                            WHEN 0 THEN ' CHECK '
                                ELSE ' NOCHECK '
                        END
                    + 'CONSTRAINT ' 
                    + QUOTENAME(@constraint_name)
                    + ';';
        --PRINT @tsql;
        INSERT sync_createCHECK 
                        (
                        Script
                        )
                        VALUES (
                                @tsql
                                )   
        END;

    FETCH NEXT FROM FKcursor INTO 
    @schema_name
    , @table_name
    , @constraint_name
    , @referenced_object_name
    , @constraint_object_id
    , @is_disabled
    , @is_not_for_replication
    , @is_not_trusted
    , @delete_referential_action
    , @update_referential_action
    , @referenced_schema_name;

END;

CLOSE FKcursor;

DEALLOCATE FKcursor;

--SELECT * FROM sync_DropFK
--SELECT * FROM sync_CreateFK
--SELECT * FROM sync_CreateCHECK
---------------------------------------------------------------------------
2.)
-----------------------------------------------------------------------------------------------------------------
----------------------------execute Drop FK Scripts --------------------------------------------------

DECLARE @scriptD NVARCHAR(4000)

DECLARE DropFKCursor CURSOR FOR
    SELECT Script 
    FROM sync_dropFK WITH (NOLOCK)

OPEN DropFKCursor

FETCH NEXT FROM DropFKCursor
INTO @scriptD

WHILE @@FETCH_STATUS = 0
BEGIN
--PRINT @scriptD
EXEC (@scriptD)
FETCH NEXT FROM DropFKCursor
INTO @scriptD
END
CLOSE DropFKCursor
DEALLOCATE DropFKCursor
--------------------------------------------------------------------------------
3.) 

------------------------------------------------------------------------------------------------------------------
----------------------------Truncate all tables in the database other than our staging tables --------------------
------------------------------------------------------------------------------------------------------------------


EXEC sp_MSforeachtable 'IF OBJECT_ID(''?'') NOT IN 
(
ISNULL(OBJECT_ID(''dbo.sync_createCHECK''),0),
ISNULL(OBJECT_ID(''dbo.sync_createFK''),0),
ISNULL(OBJECT_ID(''dbo.sync_dropFK''),0)
)
BEGIN TRY
 TRUNCATE TABLE ?
END TRY
BEGIN CATCH
 PRINT ''Truncation failed on''+ ? +''
END CATCH;' 
GO
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
----------------------------execute Create FK Scripts and CHECK CONSTRAINT Scripts---------------
----------------------------tack me at the end of the ETL in a SQL task-------------------------
-------------------------------------------------------------------------------------------------
DECLARE @scriptC NVARCHAR(4000)

DECLARE CreateFKCursor CURSOR FOR
    SELECT Script 
    FROM sync_createFK WITH (NOLOCK)

OPEN CreateFKCursor

FETCH NEXT FROM CreateFKCursor
INTO @scriptC

WHILE @@FETCH_STATUS = 0
BEGIN
--PRINT @scriptC
EXEC (@scriptC)
FETCH NEXT FROM CreateFKCursor
INTO @scriptC
END
CLOSE CreateFKCursor
DEALLOCATE CreateFKCursor
-------------------------------------------------------------------------------------------------
DECLARE @scriptCh NVARCHAR(4000)

DECLARE CreateCHECKCursor CURSOR FOR
    SELECT Script 
    FROM sync_createCHECK WITH (NOLOCK)

OPEN CreateCHECKCursor

FETCH NEXT FROM CreateCHECKCursor
INTO @scriptCh

WHILE @@FETCH_STATUS = 0
BEGIN
--PRINT @scriptCh
EXEC (@scriptCh)
FETCH NEXT FROM CreateCHECKCursor
INTO @scriptCh
END
CLOSE CreateCHECKCursor
DEALLOCATE CreateCHECKCursor

7

Kısıtlamayı bulun

SELECT * 
FROM sys.foreign_keys
WHERE referenced_object_id = object_id('TABLE_NAME')

Bu SQL tarafından oluşturulan SQL'i yürütün

SELECT 
    'ALTER TABLE ' +  OBJECT_SCHEMA_NAME(parent_object_id) +
    '.[' + OBJECT_NAME(parent_object_id) + 
    '] DROP CONSTRAINT ' + name
FROM sys.foreign_keys
WHERE referenced_object_id = object_id('TABLE_NAME')

Safeway.

Not: Tablonun herhangi bir kısıtlama hatası olmadan düşürülebilmesi veya değiştirilebilmesi için kısıtlamanın düşürülmesi için bir çözüm eklendi.


3

Tablo tasarımına sağ tıklayın ve İlişkiler'e gidin ve sol taraftaki bölmede ve sağ taraftaki bölmede yabancı anahtarı seçin, Yabancı anahtar sınırlamasını zorunlu kılın 'Evet' (yabancı anahtar kısıtlamalarını etkinleştirmek için) veya 'Hayır' ( devre dışı bırak). resim açıklamasını buraya girin


3

'905' işaretli yanıt iyi görünüyor ancak çalışmıyor.

Aşağıdaki benim için çalıştı. Herhangi Birincil Anahtar, Unique Key, veya Varsayılan kısıtlamalar CAN NOT devre dışı. Aslında, status_enabled içinde 'sp_helpconstraint '' gösterileri 'n / a' eğer - Means o olabilir DEĞİL etkin olması / devre dışı.

- DISABLE (devre dışı bırakılacak) için komut dosyası oluşturmak

select 'ALTER TABLE ' + object_name(id) + ' NOCHECK CONSTRAINT [' + object_name(constid) + ']'
from sys.sysconstraints 
where status & 0x4813 = 0x813 order by object_name(id)

- ETKİNLEŞTİRilecek komut dosyası oluşturmak için

select 'ALTER TABLE ' + object_name(id) + ' CHECK CONSTRAINT [' + object_name(constid) + ']'
from sys.sysconstraints 
where status & 0x4813 = 0x813 order by object_name(id)

3

Yabancı anahtar kısıtlamalarını, diğer kısıtlamaları geçici olarak devre dışı bıraktığınız gibi devre dışı bırakabilmeniz gerekir:

Alter table MyTable nocheck constraint FK_ForeignKeyConstraintName

Kısıtlama adında listelenen ilk tabloda kısıtlamayı devre dışı bıraktığınızdan emin olun. Örneğin, yabancı anahtar kısıtlamam FK_LocationsEmployeesLocationIdEmployeeId ise, aşağıdakileri kullanmak isterim:

Alter table Locations nocheck constraint FK_LocationsEmployeesLocationIdEmployeeId

bu kısıtlamayı ihlal etmek, çatışmanın kaynağı olarak bu tabloyu zorunlu olarak belirtmeyen bir hata üretmesine rağmen.


1

Hepsine hükmedecek bir komut dosyası: bu, kesme ve silme komutlarını sp_MSforeachtable ile birleştirir, böylece kısıtlamaları bırakıp yeniden oluşturmayı önleyebilirsiniz - sadece kesilmek yerine silinmesi gereken tabloları belirtin ve amacım için iyi bir şema filtresi ekledim tedbir (2008r2'de test edilmiştir)

declare @schema nvarchar(max) = 'and Schema_Id=Schema_id(''Value'')'
declare @deletiontables nvarchar(max) = '(''TableA'',''TableB'')'
declare @truncateclause nvarchar(max) = @schema + ' and o.Name not in ' +  + @deletiontables;
declare @deleteclause nvarchar(max) = @schema + ' and o.Name in ' + @deletiontables;        

exec sp_MSforeachtable 'alter table ? nocheck constraint all', @whereand=@schema
exec sp_MSforeachtable 'truncate table ?', @whereand=@truncateclause
exec sp_MSforeachtable 'delete from ?', @whereand=@deleteclause
exec sp_MSforeachtable 'alter table ? with check check constraint all', @whereand=@schema

1

Tablolarınızdaki kısıtlamaları geçici olarak devre dışı bırakabilir, çalışabilir, ardından yeniden oluşturabilirsiniz.

İşte bunu yapmanın kolay bir yolu ...

Tüm yabancı anahtarları devre dışı bırakacak birincil anahtarlar da dahil olmak üzere tüm dizinleri devre dışı bırakın, ardından onlarla çalışabilmeniz için yalnızca birincil anahtarları yeniden etkinleştirin ...

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON [' + t.[name] + '] DISABLE;'+CHAR(13)
from  
    sys.tables t
where type='u'

select @sql = @sql +
    'ALTER INDEX ' + i.[name] + ' ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.key_constraints i
join
    sys.tables t on i.parent_object_id=t.object_id
where
    i.type='PK'


exec dbo.sp_executesql @sql;
go

[Veri yüklemek gibi bir şey yapın]

Ardından dizinleri yeniden etkinleştirin ve yeniden oluşturun ...

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.tables t
where type='u'

exec dbo.sp_executesql @sql;
go

Bu umut verici görünüyordu, ama @sqlher zaman kesiliyor. :(
Will Strohl

1

Eğer ilgileniyorsanız daha kullanışlı bir versiyonum var. Bağlantının artık aktif olmadığı bir web sitesini buradan biraz kod kaldırdım. Saklı yordam içine tablolar bir dizi izin vermek için değiştirilmiş ve hepsini yürütmeden önce damla, kesilmiş, deyimler ekleyin. Bu, hangi tabloların kırpılması gerektiğine karar vermenizi sağlar.

/****** Object:  UserDefinedTableType [util].[typ_objects_for_managing]    Script Date: 03/04/2016 16:42:55 ******/
CREATE TYPE [util].[typ_objects_for_managing] AS TABLE(
    [schema] [sysname] NOT NULL,
    [object] [sysname] NOT NULL
)
GO

create procedure [util].[truncate_table_with_constraints]
@objects_for_managing util.typ_objects_for_managing readonly

--@schema sysname
--,@table sysname

as 
--select
--    @table = 'TABLE',
--    @schema = 'SCHEMA'

declare @exec_table as table (ordinal int identity (1,1), statement nvarchar(4000), primary key (ordinal));

--print '/*Drop Foreign Key Statements for ['+@schema+'].['+@table+']*/'

insert into @exec_table (statement)
select
          'ALTER TABLE ['+SCHEMA_NAME(o.schema_id)+'].['+ o.name+'] DROP CONSTRAINT ['+fk.name+']'
from sys.foreign_keys fk
inner join sys.objects o
          on fk.parent_object_id = o.object_id
where 
exists ( 
select * from @objects_for_managing chk 
where 
chk.[schema] = SCHEMA_NAME(o.schema_id)  
and 
chk.[object] = o.name
) 
;
          --o.name = @table and
          --SCHEMA_NAME(o.schema_id)  = @schema

insert into @exec_table (statement) 
select
'TRUNCATE TABLE ' + src.[schema] + '.' + src.[object] 
from @objects_for_managing src
; 

--print '/*Create Foreign Key Statements for ['+@schema+'].['+@table+']*/'
insert into @exec_table (statement)
select 'ALTER TABLE ['+SCHEMA_NAME(o.schema_id)+'].['+o.name+'] ADD CONSTRAINT ['+fk.name+'] FOREIGN KEY (['+c.name+']) 
REFERENCES ['+SCHEMA_NAME(refob.schema_id)+'].['+refob.name+'](['+refcol.name+'])'
from sys.foreign_key_columns fkc
inner join sys.foreign_keys fk
          on fkc.constraint_object_id = fk.object_id
inner join sys.objects o
          on fk.parent_object_id = o.object_id
inner join sys.columns c
          on      fkc.parent_column_id = c.column_id and
                   o.object_id = c.object_id
inner join sys.objects refob
          on fkc.referenced_object_id = refob.object_id
inner join sys.columns refcol
          on fkc.referenced_column_id = refcol.column_id and
                   fkc.referenced_object_id = refcol.object_id
where 
exists ( 
select * from @objects_for_managing chk 
where 
chk.[schema] = SCHEMA_NAME(o.schema_id)  
and 
chk.[object] = o.name
) 
;

          --o.name = @table and
          --SCHEMA_NAME(o.schema_id)  = @schema



declare @looper int , @total_records int, @sql_exec nvarchar(4000)

select @looper = 1, @total_records = count(*) from @exec_table; 

while @looper <= @total_records 
begin

select @sql_exec = (select statement from @exec_table where ordinal =@looper)
exec sp_executesql @sql_exec 
print @sql_exec 
set @looper = @looper + 1
end

Cevabınızdaki ölü bağlantı. Boş bir makaleyi gösterir.
Neolisk

Merhaba, bir deadlink olabilir ama kodun tamamı parçada belirtilmiştir. Bundaki sorun ne?
Zak Willis

Yanlış bir şey yok, ama muhtemelen cevabınızı düzenlemeli ve ölü bağlantıyı kaldırmalısınız.
Neolisk
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.