Обмеження зовнішнього ключа SRO 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')

Примітка: згенерована таблиця містить висловлювання для видалення окремих обмежень для запуску в іншому запиті. У моєму випадку це творило чудеса, оскільки мені потрібно було позбутися непотрібної таблиці (для тестування), зберігаючи решту таблиць, у яких ФК було недоторканим.
— Маурісіо Кінтана

1
Мені довелося використовувати parent_object_id замість referenced_object_id
— Том Робінсон

2
Альтернативою оператору SELECT для отримання всіх таблиць посилань є: EXEC sp_fkeys 'Student';
— Buggieboy

невелике коригування цього запиту 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 ('Студент') замінити [ім'я] з назвою
— CONSTRAINT

1
Як призначити останній вибір як змінну та виконати його?
— Хрвое Т

44

У SQL Server Management Studio 2008 (R2) та новіших версіях ви можете натиснути правою кнопкою миші на

БД -> Завдання -> Створення скриптів

  • Виберіть таблиці, які ви хочете знищити.

  • Виберіть "Зберегти у новому вікні запиту".

  • Натисніть кнопку Додатково.

  • Встановіть сценарій DROP та CREATE на DROP для сценарію.

  • Встановити Іноземні клавіші сценарію на "True".

  • Натисніть кнопку ОК.

  • Клацніть Далі -> Далі -> Готово.

  • Перегляньте сценарій, а потім Виконати.


12
все одно той самий "Не вдалося скинути об'єкт" my_table ", оскільки на нього посилається обмеження FOREIGN KEY.
— FrenkyB

6
Як ця відповідь має 28 + рейтинг поза мною ... все ще не працює товариш
— AltF4_

1
Хоча він генерує скрипт - цей скрипт не вирішує проблему, на яку випадає таблиця, на яку посилаються обмеження іноземного ключа.
— Олексій Шевельов

Працювало як шарм для мене.
— Йоган

21

Якщо ви спустите таблицю "дочірня" спочатку, також буде видалений зовнішній ключ. Якщо ви спробуєте спустити таблицю "батьків" спочатку, ви отримаєте "Не вдалося викинути об'єкт" a ", оскільки на нього посилається обмеження FOREIGN KEY." помилка.


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

4
Правда, і рішення, якщо мета полягає в тому, як зазначено: "Якщо я хочу видалити всі таблиці з моєї бази даних ..."
— Філіп Келлі

4
це набагато краща відповідь, ніж прийнята, враховуючи, що
— запитуючий

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
Привіт, я намагався скинути свої обмеження на зовнішній ключ вищезазначеним, але коли я йду потім опускати таблицю, він постійно говорить: "Не вдалося відкинути об'єкт, оскільки на нього все ще посилається обмеження зовнішнього ключа ... будь-які ідеї? Дякую заздалегідь
— daniness

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, ви можете скасувати обмеження зовнішніх ключів з інтерфейсу користувача. Якщо ви хочете видалити таблицю, Diaryале у таблиці користувача є зовнішній ключ, що 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 Bit важко здогадатися, при якому '=' ви отримуєте цю помилку.
— Els den Iep

3
foreign_key_checksне працюватиме на сервері MSSQL. Я думаю, що це специфічна змінна MySql.
— ooXei1sh

1
@ ooXei1sh Ні, не на MSSQL. Ось чому я кажу на початку своєї публікації: "Якщо ви перебуваєте на сервері MYSQL".
— Els den Iep

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.