关于SQL Server:如何使用T-SQL临时禁用外键约束?

How can foreign key constraints be temporarily disabled using T-SQL?

SQL Server是否支持禁用和启用外键约束?或者我唯一的选择是选择drop,然后重新选择create的约束条件?


如果你想禁用所有约束在数据库刚刚运行这个代码:

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

他们在转换运行:(打印,当然是可选的,它只是上市的表)

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

当我找到它有用的数据从一个到另一个populating数据库。最好的方法是多约束比下降。当你提到它是手机掉所有的数据在数据库和IT(repopulating说在测试环境)。

如果你是通过您的所有数据,你可以找到这样的解决方案是有益的。

所以有时它是一个禁用所有触发器为好的手机,你可以看到完整的解决方案在这里。


http://www.sqljunkies.com /博客/小说/档案/ 2005/01/30/7037.aspx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 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


您的最佳的选择是删除和创建对外键约束。

我不喜欢在这工作的例子后,将"我是",也不工作,如果一个外键引用不同的工作模式,其他的人也不多,如果对外键列。考虑两个脚本,多模式和多个列,通过外资的关键。

这里是哪里,"添加脚本语句的约束",他们多做单独列由逗号(是要保存在输出之前执行拖放报表):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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

这里是哪里"脚本,删除约束"语句:

1
2
3
4
5
6
7
8
9
10
11
12
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


你有一个禁用约束使用nocheck年龄表

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

使你有一个使用双止回阀

1
ALTER TABLE [TABLE_NAME] WITH CHECK CHECK CONSTRAINT [ALL|CONSTRAINT_NAME]
  • *注意在检查时检查授权。
  • 所有在所有均值约束表。

一旦完成,如果你需要检查的地位,使用脚本列表中的约束状态。要非常礼貌:

1
2
3
4
5
6
7
8
9
10
11
    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


《SQL 92标准允许一个被约束的,这样它可以作为递延推迟(或明确implicitly在scope of a)事务。是的,仍然是一本SQL Server SQL 92的功能。

我是一个变化的约束,类似的nocheck改变数据库结构到飞掉的东西确实是约束和avoided(例如用户的需要增加的特权)。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
   --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

我也同意你,Hamlin的店。当你使用SSIS数据或传输数据时,要replicate,似乎没有必要暂时禁用或删除然后重新对外键约束或recreate启用他们。在论文的情况下,是指完整性的问题,因为它已经保持在源数据库。因此,对于这个你可以放心残余物。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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

第一篇文章:

对于OP,Kristof的解决方案将起作用,除非在大的删除上存在大量数据和事务日志气球问题。此外,即使要备用tlog存储,由于删除对tlog的写操作,对于具有数亿行的表来说,操作可能需要很长的时间。

我经常使用一系列的光标来截断和重新加载一个大型生产数据库的大型副本。解决方案为多个模式、多个外键列设计了帐户,最好是存储过程用于SSIS。

它包括创建三个临时表(实际表),以存放放置、创建和检查FK脚本,创建和插入这些脚本到表中,然后循环遍历表并执行它们。附加脚本包括四个部分:1)在三个分段(实)表中创建和存储脚本;2)通过光标逐个执行drop fk脚本;3)使用sp msforeachtable截断数据库中除三个分段表以外的所有表;4)在结束时执行create fk并检查fk脚本。您的ETL SSIS包。

在SSIS中的执行SQL任务中运行脚本创建部分。在第二个执行SQL任务中运行"execute drop fk scripts"部分。将截断脚本放入第三个执行SQL任务中,然后在控制流末尾的最后一个执行SQL任务(如果需要,可以执行两个)中附加创建和检查脚本之前,执行您需要执行的其他ETL进程。

当重新应用外键失败时,将脚本存储在实际表中已证明是非常宝贵的,因为您可以从同步创建中选择*,复制/粘贴到查询窗口中,一次运行一个,并在找到失败/仍无法重新应用的脚本后修复数据问题。

如果脚本失败,在执行之前不确保重新应用所有外键/检查,则不要重新运行该脚本,否则很可能会丢失一些创建和检查FK脚本,因为我们的临时表在创建要执行的脚本之前被删除并重新创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
----------------------------------------------------------------------------
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

几乎肯定需要WITH CHECK CHECK

这一点是在一些答案和评论中提出的,但我觉得再次提出这一点已经足够重要了。

使用以下命令(没有WITH CHECK命令)重新启用约束将有一些严重的缺点。

1
ALTER TABLE MyTable CHECK CONSTRAINT MyConstraint;

WITH CHECK | WITH NOCHECK

Specifies whether the data in the table is or is not validated against
a newly added or re-enabled FOREIGN KEY or CHECK constraint. If not
specified, WITH CHECK is assumed for new constraints, and WITH NOCHECK
is assumed for re-enabled constraints.

If you do not want to verify new CHECK or FOREIGN KEY constraints
against existing data, use WITH NOCHECK. We do not recommend doing
this, except in rare cases. The new constraint will be evaluated in
all later data updates. Any constraint violations that are suppressed
by WITH NOCHECK when the constraint is added may cause future updates
to fail if they update rows with data that does not comply with the
constraint.

The query optimizer does not consider constraints that are defined
WITH NOCHECK. Such constraints are ignored until they are re-enabled
by using ALTER TABLE table WITH CHECK CHECK CONSTRAINT ALL.

注意:WITH NOCHECK是重新启用约束的默认设置。我想知道为什么…

  • 在执行此命令期间,不会评估表中的现有数据-成功完成不能保证表中的数据根据约束有效。
  • 在对无效记录的下一次更新过程中,约束将被评估并将失败,从而导致与实际更新无关的错误。
  • 依赖约束来确保数据有效的应用程序逻辑可能会失败。
  • 查询优化器不会使用以这种方式启用的任何约束。
  • sys.foreign_keys系统视图提供了对该问题的一些可见性。注意,它有一个is_disabled和一个is_not_trusted列。is_disabled表示未来的数据操作操作是否会针对约束进行验证。is_not_trusted表示表中当前的所有数据是否已经针对约束进行了验证。

    1
    ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT MyConstraint;

    你的约束值得信任吗?找出。。。

    1
    SELECT * FROM sys.foreign_keys WHERE is_not_trusted = 1;

    找到的约束

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

    执行的SQL生成的SQL。

    1
    2
    3
    4
    5
    6
    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公司。

    注:增值解决方案降低的约束,这样可以把表或修改没有任何约束的错误。


    右键单击表设计并转到关系,选择左侧窗格和右侧窗格中的外键,将强制外键约束设置为"是"(启用外键约束)或"否"(禁用)。enter image description here


    标有"905"的答案看起来不错,但不起作用。

    跟随者为我工作。不能禁用任何主键、唯一键或默认约束。实际上,如果"sp_helpconstraint"显示"n/a"处于"启用"状态,则表示无法启用/禁用它。

    --生成要禁用的脚本

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

    --生成脚本以启用

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

    实际上,您应该能够像临时禁用其他约束一样禁用外键约束:

    1
    Alter table MyTable nocheck constraint FK_ForeignKeyConstraintName

    只需确保在约束名称中列出的第一个表上禁用约束。例如,如果我的外键约束是fk locationsEmployeeSlocationIdEmployeeID,我将使用以下内容:

    1
    Alter table Locations nocheck constraint FK_LocationsEmployeesLocationIdEmployeeId

    即使违反此约束,也会产生一个错误,该错误不一定将该表作为冲突的源。


    您可以临时禁用表上的约束,进行工作,然后重新生成它们。

    这是一个简单的方法…

    禁用所有索引,包括主键,这将禁用所有外键,然后仅重新启用主键,以便您可以使用它们…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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

    [做一些事情,比如加载数据]

    然后重新启用并重建索引…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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

    如果你感兴趣的话,我有一个更有用的版本。我从一个链接不再活跃的网站上提取了一些代码。我修改了它,允许在存储过程中有一个表数组,它在执行所有语句之前填充drop、truncate和add语句。这使您可以控制哪些表需要截断。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    /****** 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


    一个脚本将它们全部规则化:这将truncate和delete命令与sp msforeachtable结合在一起,这样可以避免删除和重新创建约束-只需指定需要删除而不是截断的表,出于我的目的,我还包含了一个额外的模式过滤器,用于良好的度量(在2008r2中测试)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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