Подтвердить что ты не робот

Как удалить все ограничения внешнего ключа во всех таблицах?

Я хочу написать команду sql, чтобы удалить все ограничения во всех таблицах. Я искал в Интернете и нашел следующее, которое отлично работает, если база данных небольшая и не сложная.

DECLARE @name VARCHAR(128) 
DECLARE @constraint VARCHAR(254) 
DECLARE @SQL VARCHAR(254) 
DECLARE @schema VARCHAR(128)

SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME) 
SELECT @schema = (SELECT TOP 1 schema_name(schema_id) FROM sys.objects WHERE [name] = @name) 

WHILE @name is not null 
BEGIN 
    SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME) 
    WHILE @constraint IS NOT NULL 
    BEGIN 
        SELECT @SQL = 'ALTER TABLE ' + @schema + '.[' + RTRIM(@name) +'] DROP CONSTRAINT [' + RTRIM(@constraint) +']' 
        EXEC (@SQL) 
        PRINT 'Dropped FK Constraint: ' + @constraint + ' on ' + @name 
        SELECT @constraint = (SELECT TOP 1 CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' AND CONSTRAINT_NAME <> @constraint AND TABLE_NAME = @name ORDER BY CONSTRAINT_NAME) 
    END 
SELECT @name = (SELECT TOP 1 TABLE_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE constraint_catalog=DB_NAME() AND CONSTRAINT_TYPE = 'FOREIGN KEY' ORDER BY TABLE_NAME) 
SELECT @schema = (SELECT TOP 1 schema_name(schema_id) FROM sys.objects WHERE [name] = @name) 
END 
GO 

Это не работает, если я запускаю его с более сложной базой данных или даже с AdventureWork. Он показывает некоторые erros, как показано ниже.

Msg 3728, Level 16, State 1, Line 1
'FK_ap_invoice_modification_type_id' is not a constraint.
Msg 3727, Level 16, State 0, Line 1
Could not drop constraint. See previous errors.
Msg 3725, Level 16, State 0, Line 1
The constraint 'PK_ap_invoice' is being referenced by table '_drop_now_ap_invoice_detail', foreign key constraint 'FK_ap_invoice_detail_ap_invoice'.
Msg 3727, Level 16, State 0, Line 1
Could not drop constraint. See previous errors.

Причина в том, что некоторые FK ссылаются на другую таблицу. Я должен запустить этот script пару раз, пока база данных не станет чистой.

Я хочу знать, как я могу удалить все FK в базе данных.

4b9b3361

Ответ 1

Существует много информации об этом предмете. Проверьте этот подробный ответ от @AaronBertrand. В нем говорится о временном отключении внешних ключей, но, читая все это и изменяя, у вас будет приятный script, чтобы играть и добиваться многого.

С моей стороны я могу предложить 2 разных сценария, чтобы получить все внешние ключи. В обоих случаях раскомментируйте --EXEC (@SQL), чтобы выполнить код ALTER. Или вы можете подождать, пока он не распечатает все предложения alter, а затем скопируйте их, чтобы выполнить их.

Сначала используется INFORMATION_SCHEMA для получения ограничений:

DECLARE @SQL VARCHAR(MAX)=''
SELECT @SQL = @SQL + 'ALTER TABLE ' + QUOTENAME(FK.TABLE_SCHEMA) + '.' + QUOTENAME(FK.TABLE_NAME) + ' DROP CONSTRAINT [' + RTRIM(C.CONSTRAINT_NAME) +'];' + CHAR(13)
--SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME
  FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
 INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
    ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
 INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
    ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
    ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
 INNER JOIN (
            SELECT i1.TABLE_NAME, i2.COLUMN_NAME
              FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
             INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2
                ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
            WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
           ) PT
    ON PT.TABLE_NAME = PK.TABLE_NAME

--EXEC (@SQL)

PRINT @SQL

Этот параметр использует разные системные представления и таблицу CTE.

DECLARE @SQL varchar(4000)=''
;WITH ReferencingFK AS 
(
    SELECT fk.Name AS 'FKName', OBJECT_NAME(fk.parent_object_id) 'ParentTable',
            cpa.name 'ParentColumnName', OBJECT_NAME(fk.referenced_object_id) 'ReferencedTable',
            cref.name 'ReferencedColumnName'
    FROM sys.foreign_keys fk
    INNER JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
    INNER JOIN sys.columns cpa ON fkc.parent_object_id = cpa.object_id AND fkc.parent_column_id = cpa.column_id
    INNER JOIN sys.columns cref ON fkc.referenced_object_id = cref.object_id AND fkc.referenced_column_id = cref.column_id
)
SELECT @SQL = @SQL + 'ALTER TABLE ' + ParentTable + ' DROP CONSTRAINT [' + RTRIM(FKName) +'];' + CHAR(13)
--SELECT FKName, ParentTable, ParentColumnName, ReferencedTable, ReferencedColumnName
  FROM ReferencingFK
 WHERE ReferencedTable = 'Employee'
 ORDER BY ParentTable, ReferencedTable, FKName

--EXEC (@SQL) 

PRINT @SQL

Ответ 2

Я улучшил первый script, предоставленный @Yaroslav и script, предоставленный @Quandary, поэтому они теперь работают для баз данных, SQL-запрос которых по умолчанию удаляет все внешние ключи, превышает размер, выделенный для SQL переменные (4000 или MAX).

Измененные сценарии отбрасывают 5 внешние ключи на итерацию (просто для того, чтобы быть безопасным, реализовано добавлением TOP 5). Сценарии останавливаются, когда нет внешнего ключа, который нужно оставить (переменная SQL остается пустой после запуска SELECT).

Первый script by @Yaroslav

DECLARE @SQL varchar(4000)
IterationStart:
SET @SQL=''
SELECT TOP 5 @SQL = @SQL + 'ALTER TABLE ' + FK.TABLE_NAME + ' DROP CONSTRAINT [' + RTRIM(C.CONSTRAINT_NAME) +'];' + CHAR(13)
  FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
 INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
    ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
 INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
    ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
    ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
 INNER JOIN (
            SELECT i1.TABLE_NAME, i2.COLUMN_NAME
              FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
             INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2
                ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
            WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
           ) PT
    ON PT.TABLE_NAME = PK.TABLE_NAME
IF @SQL <> ''
BEGIN
  EXEC(@SQL)
  GOTO IterationStart
END

Script by @Quandary

DECLARE @sql nvarchar(MAX) 

IterationStart:
SET @sql = '' 

SELECT TOP 5 @sql = @sql + 'ALTER TABLE ' + QUOTENAME(RC.CONSTRAINT_SCHEMA) 
    + '.' + QUOTENAME(KCU1.TABLE_NAME) 
    + ' DROP CONSTRAINT ' + QUOTENAME(rc.CONSTRAINT_NAME) + '; ' 
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC 

INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1 
    ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG  
    AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA 
    AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME 

IF @SQL <> ''
BEGIN
  EXEC(@SQL)
  GOTO IterationStart
END

Ответ 3

Самый простой вариант:

DECLARE @sql nvarchar(MAX) 
SET @sql = '' 

SELECT @sql = @sql + 'ALTER TABLE ' + QUOTENAME(RC.CONSTRAINT_SCHEMA) 
    + '.' + QUOTENAME(KCU1.TABLE_NAME) 
    + ' DROP CONSTRAINT ' + QUOTENAME(rc.CONSTRAINT_NAME) + '; ' 
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC 

INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1 
    ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG  
    AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA 
    AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME 


-- PRINT @sql 
EXECUTE(@sql) 

Ответ 4

Здесь короткий и сладкий script я использую (на SQL Server 2008 и выше), чтобы удалить все внешние ключи, которые также учитывают схему объекта:

declare @sql varchar(max) = (
    select 
        'alter table ' + quotename(schema_name(schema_id)) + '.' +
        quotename(object_name(parent_object_id)) +
        ' drop constraint '+quotename(name) + ';'
    from sys.foreign_keys
    for xml path('')
);
exec sp_executesql @sql;

Ответ 5

Я использовал решение INFORMATION_SCHEMA, упомянутое @Yaroslav, но в моей базе данных было слишком много констант внешнего ключа, чтобы поместить их в varchar (MAX). Поэтому мне пришлось изменить script, чтобы вместо этого использовать временную таблицу и курсор.

Кроме того, я добавил [] вокруг имени таблицы.

DECLARE @SQL TABLE (Command VARCHAR(MAX))

INSERT @SQL
SELECT 'ALTER TABLE [' + FK.TABLE_NAME + '] DROP CONSTRAINT [' + RTRIM(C.CONSTRAINT_NAME) +'];' + CHAR(13)
  FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
 INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
    ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
 INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
    ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU
    ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
 INNER JOIN (
            SELECT i1.TABLE_NAME, i2.COLUMN_NAME
              FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
             INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2
                ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
            WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
           ) PT
    ON PT.TABLE_NAME = PK.TABLE_NAME

DECLARE cmdCursor CURSOR
    FOR SELECT Command FROM @SQL
OPEN cmdCursor
DECLARE @Command VARCHAR(MAX)

FETCH NEXT FROM cmdCursor INTO @Command
WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT @Command
    EXEC (@Command)
    FETCH NEXT FROM cmdCursor INTO @Command
END

CLOSE cmdCursor;
DEALLOCATE cmdCursor;

Ответ 6

CREATE TABLE #Commands (Command VARCHAR(MAX))

INSERT #Commands
SELECT 'ALTER TABLE ' + QUOTENAME(RC.CONSTRAINT_SCHEMA)
    + '.' + QUOTENAME(KCU1.TABLE_NAME)
    + ' DROP CONSTRAINT ' + QUOTENAME(rc.CONSTRAINT_NAME) + '; '
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC

INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1
    ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
    AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
    AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
WHERE ORDINAL_POSITION=1

--SELECT * FROM #Commands

DECLARE @Command VARCHAR(MAX)
DECLARE curCommand CURSOR FOR
SELECT Command FROM #Commands

OPEN curCommand

FETCH NEXT FROM curCommand INTO @Command

WHILE @@FETCH_STATUS =0
BEGIN

    EXEC(@Command)
    FETCH NEXT FROM curCommand INTO @Command

END

CLOSE curCommand
DEALLOCATE curCommand

DROP TABLE #Commands