Ограничение внешнего ключа SQL DROP TABLE


154

Если я хочу удалить все таблицы в моей базе данных, как это, позаботится ли об ограничении внешнего ключа? Если нет, то как мне позаботиться об этом в первую очередь?

GO
IF OBJECT_ID('dbo.[Course]','U') IS NOT NULL
    DROP TABLE dbo.[Course]
GO
IF OBJECT_ID('dbo.[Student]','U') IS NOT NULL
    DROP TABLE dbo.[Student]


2
Проверьте этот ответ, он мне помог;) stackoverflow.com/a/5488670/2205144
xatz

Ответы:


335

Нет, это не удалит вашу таблицу, если на нее действительно ссылаются внешние ключи.

Чтобы получить все отношения внешних ключей, ссылающиеся на вашу таблицу, вы можете использовать этот SQL (если вы используете SQL Server 2005 и выше):

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

и если они есть, с этим оператором здесь, вы можете создать операторы SQL, чтобы фактически отбросить эти отношения FK:

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('Student')

Примечание: сгенерированная таблица содержит операторы для удаления отдельных ограничений, которые будут выполняться в другом запросе. В моем случае это творило чудеса, так как мне нужно было избавиться от бесполезной таблицы (для целей тестирования), сохраняя при этом остальные таблицы, в которых был FK.
Маурисио Кинтана

1
Мне пришлось использовать parent_object_id вместо referenced_object_id
Том Робинсон

2
Альтернативой оператору SELECT для получения всех ссылочных таблиц является: EXEC sp_fkeys 'Student';
Buggieboy

небольшая настройка этого запроса ВЫБЕРИТЕ '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 ('имя студента)) с ОГРАНИЧЕННЫМ именем
Стас Свишов

1
Как назначить ваш последний выбор в качестве переменной и выполнить его?
Hrvoje T

44

В SQL Server Management Studio 2008 (R2) и новее вы можете щелкнуть правой кнопкой мыши на

БД -> Задачи -> Генерация скриптов

  • Выберите таблицы, которые вы хотите DROP.

  • Выберите «Сохранить в новом окне запроса».

  • Нажмите на кнопку Дополнительно.

  • Установите Script DROP и CREATE на Script DROP.

  • Установите для внешних ключей скрипта значение True.

  • Нажмите ОК.

  • Нажмите Далее -> Далее -> Готово.

  • Просмотрите сценарий и затем выполните.


12
все тот же «Не удалось удалить объект« my_table », поскольку на него ссылается ограничение FOREIGN KEY.
FrenkyB

6
То, как этот ответ имеет рейтинг 28 +, выше моего
понимания

1
Хотя он генерирует сценарий - этот сценарий не решает проблему, которая заключается в удалении таблицы, на которую ссылаются ограничения внешнего ключа.
Алексей Шевелев

Работал как шарм для меня.
Йохан

21

Если вы сначала удалите «дочернюю» таблицу, внешний ключ также будет удален. Если вы попытаетесь сначала удалить «родительскую» таблицу, вы получите «Не удалось удалить объект« a », поскольку на него ссылается ограничение FOREIGN KEY». ошибка.


2
Правда, но нет решения. У дочернего элемента могут быть внешние ключи для других таблиц, и / или вы, возможно, не захотите бросить его в первую очередь.
MaR

4
Правда, и решение, если цель, как указано, «Если я хочу удалить все таблицы в моей базе данных ...»
Филипп Келли

4
это гораздо лучший ответ, чем принятый, учитывая, что спрашивающий хочет «удалить все таблицы в моей базе данных»
lukkea

17

Вот еще один способ правильно отбросить все таблицы, используя sp_MSdropconstraintsпроцедуру. Самый короткий код, который я мог придумать:

exec sp_MSforeachtable "declare @name nvarchar(max); set @name = parsename('?', 1); exec sp_MSdropconstraints @name";
exec sp_MSforeachtable "drop table ?";

Удивительный мужчина ............
edCoder


2

Чуть более общая версия того, что разместил @mark_s, это помогло мне

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

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


1
Привет! Я пытался отбросить ограничения внешнего ключа, описанные выше, но когда я потом отбрасываю таблицу, он продолжает говорить: «Не удалось удалить объект, поскольку на него все еще ссылается ограничение внешнего ключа ...» какие-нибудь идеи? Спасибо заранее.
Дани

1

Вот еще один способ удалить все ограничения, за которыми следуют сами таблицы, используя прием конкатенации, FOR XML PATH('')который позволяет объединить несколько входных строк в одну выходную строку. Должен работать на любом SQL 2005 и более поздних версиях.

Я оставил команды EXECUTE закомментированными для безопасности.

DECLARE @SQL NVARCHAR(max)
;WITH fkeys AS (
    SELECT quotename(s.name) + '.' + quotename(o.name) tablename, quotename(fk.name) constraintname 
    FROM sys.foreign_keys fk
    JOIN sys.objects o ON fk.parent_object_id = o.object_id
    JOIN sys.schemas s ON o.schema_id = s.schema_id
)
SELECT @SQL = STUFF((SELECT '; ALTER TABLE ' + tablename + ' DROP CONSTRAINT ' + constraintname
FROM fkeys
FOR XML PATH('')),1,2,'')

-- EXECUTE(@sql)

SELECT @SQL = STUFF((SELECT '; DROP TABLE ' + quotename(TABLE_SCHEMA) + '.' + quotename(TABLE_NAME) 
FROM INFORMATION_SCHEMA.TABLES 
FOR XML PATH('')),1,2,'')

-- EXECUTE(@sql)

Это не работает хорошо, потому что не все FK будут удалены (только те, где наши таблицы используются как родительские, где мы должны удалить также ограничение, где наша таблица использовалась как «ссылка»).
Роман Покровский

Роман, оригинальный пост о снятии ограничений внешнего ключа. Мой ответ не ставит целью охватить что-то помимо этого.
Уоррен Румак

1

Вот полный скрипт для реализации решения:

create Procedure [dev].DeleteTablesFromSchema
(
    @schemaName varchar(500)
)
As 
begin
    declare @constraintSchemaName nvarchar(128), @constraintTableName nvarchar(128),  @constraintName nvarchar(128)
    declare @sql nvarchar(max)
    -- delete FK first
    declare cur1 cursor for
    select distinct 
    CASE WHEN t2.[object_id] is NOT NULL  THEN  s2.name ELSE s.name END as SchemaName,
    CASE WHEN t2.[object_id] is NOT NULL  THEN  t2.name ELSE t.name END as TableName,
    CASE WHEN t2.[object_id] is NOT NULL  THEN  OBJECT_NAME(d2.constraint_object_id) ELSE OBJECT_NAME(d.constraint_object_id) END as ConstraintName
    from sys.objects t 
        inner join sys.schemas s 
            on t.[schema_id] = s.[schema_id]
        left join sys.foreign_key_columns d 
            on  d.parent_object_id = t.[object_id]
        left join sys.foreign_key_columns d2 
            on  d2.referenced_object_id = t.[object_id]
        inner join sys.objects t2 
            on  d2.parent_object_id = t2.[object_id]
        inner join sys.schemas s2 
            on  t2.[schema_id] = s2.[schema_id]
    WHERE t.[type]='U' 
        AND t2.[type]='U'
        AND t.is_ms_shipped = 0 
        AND t2.is_ms_shipped = 0 
        AND s.Name=@schemaName
    open cur1
    fetch next from cur1 into @constraintSchemaName, @constraintTableName, @constraintName
    while @@fetch_status = 0
    BEGIN
        set @sql ='ALTER TABLE ' + @constraintSchemaName + '.' + @constraintTableName+' DROP CONSTRAINT '+@constraintName+';'
        exec(@sql)
        fetch next from cur1 into @constraintSchemaName, @constraintTableName, @constraintName
    END
    close cur1
    deallocate cur1

    DECLARE @tableName nvarchar(128)
    declare cur2 cursor for
    select s.Name, p.Name
    from sys.objects p
        INNER JOIN sys.schemas s ON p.[schema_id] = s.[schema_id]
    WHERE p.[type]='U' and is_ms_shipped = 0 
    AND s.Name=@schemaName
    ORDER BY s.Name, p.Name
    open cur2

    fetch next from cur2 into @schemaName,@tableName
    while @@fetch_status = 0
    begin
        set @sql ='DROP TABLE ' + @schemaName + '.' + @tableName
        exec(@sql)
        fetch next from cur2 into @schemaName,@tableName
    end

    close cur2
    deallocate cur2

end
go

1
Removing Referenced FOREIGN KEY Constraints
Assuming there is a parent and child table Relationship in SQL Server:

--First find the name of the Foreign Key Constraint:
  SELECT * 
  FROM sys.foreign_keys
  WHERE referenced_object_id = object_id('States')

--Then Find foreign keys referencing to dbo.Parent(States) table:
   SELECT name AS 'Foreign Key Constraint Name', 
           OBJECT_SCHEMA_NAME(parent_object_id) + '.' + OBJECT_NAME(parent_object_id) AS 'Child Table'
   FROM sys.foreign_keys 
   WHERE OBJECT_SCHEMA_NAME(referenced_object_id) = 'dbo' AND 
              OBJECT_NAME(referenced_object_id) = 'dbo.State'

 -- Drop the foreign key constraint by its name 
   ALTER TABLE dbo.cities DROP CONSTRAINT FK__cities__state__6442E2C9;

 -- You can also use the following T-SQL script to automatically find 
 --and drop all foreign key constraints referencing to the specified parent 
 -- table:

 BEGIN

DECLARE @stmt VARCHAR(300);

-- Cursor to generate ALTER TABLE DROP CONSTRAINT statements  
 DECLARE cur CURSOR FOR
 SELECT 'ALTER TABLE ' + OBJECT_SCHEMA_NAME(parent_object_id) + '.' + 
 OBJECT_NAME(parent_object_id) +
                ' DROP CONSTRAINT ' + name
 FROM sys.foreign_keys 
 WHERE OBJECT_SCHEMA_NAME(referenced_object_id) = 'dbo' AND 
            OBJECT_NAME(referenced_object_id) = 'states';

 OPEN cur;
 FETCH cur INTO @stmt;

 -- Drop each found foreign key constraint 
  WHILE @@FETCH_STATUS = 0
  BEGIN
    EXEC (@stmt);
    FETCH cur INTO @stmt;
  END

  CLOSE cur;
  DEALLOCATE cur;

  END
  GO

--Now you can drop the parent table:

 DROP TABLE states;
--# Command(s) completed successfully.

0

Используя SQL Server Manager, вы можете удалить ограничения внешнего ключа из пользовательского интерфейса. Если вы хотите удалить таблицу, Diaryно у таблицы User есть внешний ключ, DiaryIdуказывающий на Diaryтаблицу, вы можете развернуть (используя символ плюс) Userтаблицу, а затем развернуть Foreign Keysраздел. Щелкните правой кнопкой мыши по внешнему ключу, который указывает на таблицу дневников, затем выберите Delete. Затем вы можете развернуть Columnsраздел, щелкнуть правой кнопкой мыши и удалить столбец DiaryId. Тогда вы можете просто запустить:

drop table Diary

Я знаю, что ваш фактический вопрос касается удаления всех таблиц, так что это может быть бесполезно в этом случае. Однако, если вы просто хотите удалить несколько таблиц, я считаю, что это полезно (в заголовке явно не упоминается удаление всех таблиц).


0

Если вы работаете на сервере MySQL и не возражаете против потери таблиц, вы можете использовать простой запрос для удаления нескольких таблиц одновременно:

SET foreign_key_checks = 0;
DROP TABLE IF EXISTS table_a,table_b,table_c,table_etc;
SET foreign_key_checks = 1;

Таким образом, не имеет значения, в каком порядке вы используете таблицу в запросе.

Если кто-то собирается что-то сказать о том, что это не очень хорошее решение, если у вас есть база данных с множеством таблиц: я согласен!


Я получаюIncorrect syntax near '='. (102) (SQLExecDirectW)
Мэтт

@Matt Трудно догадаться, в каком '=' вы получите эту ошибку.
Эльс ден Ип

3
foreign_key_checksне будет работать на сервере MSSQL. Я думаю, что это специфическая переменная MySql.
ooXei1sh

1
@ ooXei1sh Нет не на MSSQL. Вот почему я говорю в начале своего поста: «Если вы находитесь на сервере MYSQL».
Эльс ден Ип

0

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

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

      SELECT name AS 'Foreign Key Constraint Name',
      OBJECT_SCHEMA_NAME(parent_object_id) + '.' + OBJECT_NAME(parent_object_id)
      AS 'Child Table' FROM sys.foreign_keys
      WHERE OBJECT_SCHEMA_NAME(referenced_object_id) = 'dbo'
      AND OBJECT_NAME(referenced_object_id) = 'dbo.roles'

Вы получите имя FK как показано ниже: FK__Table1__roleId__1X1H55C1

Теперь запустите приведенный ниже код, чтобы удалить ссылку FK, полученную сверху.

ALTER TABLE dbo.users drop CONSTRAINT FK__Table1__roleId__1X1H55C1;

Готово!


-4

Если я хочу удалить все таблицы в моей базе данных

Тогда намного проще отбросить всю базу данных:

DROP DATABASE WorkerPensions

71
Давать вам -1 за это, так как это неверный ответ на вопрос по двум важным причинам: 1) Он удаляет намного больше, чем таблицы! Хранимые процедуры, функции, UDT, безопасность, сборки .NET и т. Д. - все это уходит с DROP DATABASE. 2) Вам может быть запрещено создавать базы данных, например, среду разработки с централизованным управлением, где базы данных предоставляются ИТ-отделом и имеют дополнительные требования во время создания, о которых вы не знаете.
Уоррен Румак

-4

Если вы хотите DROPтаблицу, на которую ссылалась другая таблица с использованием внешнего ключа, используйте

DROP TABLE *table_name* CASCADE CONSTRAINTS;
Я думаю, что это должно работать для вас.


1
нет cascade constraintsна сервере sql
JackyJohnson
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.