Как можно временно отключить ограничения внешнего ключа с помощью T-SQL? - PullRequest
779 голосов
/ 01 октября 2008

Поддерживается ли отключение и включение ограничений внешнего ключа в SQL Server? Или мой единственный вариант - drop, а затем повторно create ограничения?

Ответы [ 16 ]

1 голос
/ 24 марта 2017

На самом деле вы должны иметь возможность отключить ограничения внешнего ключа так же, как вы временно отключаете другие ограничения:

Alter table MyTable nocheck constraint FK_ForeignKeyConstraintName

Просто убедитесь, что вы отключаете ограничение для первой таблицы, указанной в имени ограничения. Например, если мое ограничение внешнего ключа было FK_LocationsEmployeesLocationIdEmployeeId, я хотел бы использовать следующее:

Alter table Locations nocheck constraint FK_LocationsEmployeesLocationIdEmployeeId

даже если нарушение этого ограничения приведет к ошибке, которая не обязательно будет указывать эту таблицу как источник конфликта.

1 голос
/ 06 февраля 2017

Ответ с пометкой «905» выглядит хорошо, но не работает.

Следующее сработало для меня. Любые ограничения первичного ключа, уникального ключа или значения по умолчанию НЕ МОГУТ быть отключены. Фактически, если 'sp_helpconstraint' 'показывает' n / a 'в status_enabled - это означает, что НЕ может быть включено / отключено.

- Чтобы сгенерировать скрипт для отключения

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

- Чтобы сгенерировать скрипт для ENABLE

select 'ALTER TABLE ' + object_name(id) + ' CHECK CONSTRAINT [' + object_name(constid) + ']'
from sys.sysconstraints 
where status & 0x4813 = 0x813 order by object_name(id)
1 голос
/ 16 мая 2016

Щелкните правой кнопкой мыши дизайн таблицы и перейдите к Отношениям и выберите внешний ключ на левой панели и на правой панели, установите для параметра Принудительное ограничение внешнего ключа значение «Да» (чтобы включить ограничения внешнего ключа) или «Нет». '(чтобы отключить его). enter image description here

0 голосов
/ 02 августа 2018

Вы можете временно отключить ограничения на своих таблицах, выполнить работу, а затем перестроить их.

Вот простой способ сделать это ...

Отключите все индексы, включая первичные ключи, которые отключат все внешние ключи, затем снова включите только первичные ключи, чтобы вы могли работать с ними ...

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

[Сделайте что-нибудь, например, загрузку данных]

Затем снова включите и перестройте индексы ...

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
0 голосов
/ 15 сентября 2016

Один сценарий, чтобы управлять ими всеми: он объединяет команды усечения и удаления с sp_MSforeachtable, так что вы можете избежать удаления и воссоздания ограничений - просто укажите таблицы, которые нужно удалять, а не усекать, и для моих целей я добавил дополнительную схему фильтр для хорошей меры (проверено в 2008r2)

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
0 голосов
/ 03 апреля 2016

У меня есть более полезная версия, если вы заинтересованы. Я поднял немного кода с сайта, на котором ссылка больше не активна. Я изменил его, чтобы разрешить массив таблиц в хранимую процедуру, и он заполняет операторы drop, truncate, add перед выполнением всех их. Это дает вам возможность определять, какие таблицы нужно обрезать.

/****** 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...