Как определить, является ли таблица FileTable в SQL Server - PullRequest
0 голосов
/ 05 ноября 2019

Я работаю с существующим скриптом SQL, который удаляет все внешние ключи из базы данных. Это может привести к проблемам, если одна из таблиц - FileTable.

Основной вопрос: есть ли способ обнаружить, что конкретная таблица является FILETABLE, и пропустить сброс внешних ключей на эту таблицу?

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

DECLARE @fkdel varchar(512);

DECLARE FkCrsr CURSOR FOR 
     SELECT 'ALTER TABLE [' + TABLE_SCHEMA + '].[' + TABLE_NAME + '] DROP CONSTRAINT [' + CONSTRAINT_NAME +']' 
     FROM information_schema.table_constraints WITH (NOLOCK)
     WHERE CONSTRAINT_TYPE = 'FOREIGN KEY';

OPEN FkCrsr;

FETCH NEXT FROM FkCrsr INTO @fkdel;

WHILE @@FETCH_STATUS = 0
BEGIN;
    PRINT @fkdel;
    EXEC (@fkdel);

    FETCH NEXT FROM FkCrsr INTO @fkdel;
END;

CLOSE FkCrsr;
DEALLOCATE FkCrsr;

EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT all";

Выполнение этого в базе данных, содержащей FileTable, приводит к ошибке вроде

Сообщение 3865, Уровень 16, Состояние 1, Строка 3
Операция над объектом 'FK__DocumentS__paren__3A69DAC6' заблокирована. Объект является объектом, определяемым системой FileTable, и пользовательские изменения не допускаются.

Сообщение 3727, уровень 16, состояние 0, строка 3
Не удалось удалить ограничение. Смотрите предыдущие ошибки.

1 Ответ

1 голос
/ 05 ноября 2019

Для этого не следует использовать представления информационной схемы. Тем более, что вы заботитесь о схеме. Документация MS даже утверждает, что не использовать это. https://docs.microsoft.com/en-us/sql/relational-databases/system-information-schema-views/table-constraints-transact-sql?view=sql-server-ver15

Если вы вместо этого используете системные представления, это становится намного проще. Например, sys.tables имеет столбец «is_filetable». https://docs.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-tables-transact-sql?view=sql-server-ver15 Также обратите внимание, что я использую здесь QUOTENAME вместо добавления квадратных скобок вручную.

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

Вся ваша циклическая конструкция может быть упрощена до чего-то подобного.

declare @SQL nvarchar(max) = ''

select @SQL = @SQL + 'ALTER TABLE ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + ';'
from sys.foreign_keys fk
join sys.tables t on t.object_id = fk.parent_object_id
join sys.schemas s on s.schema_id = t.schema_id
where t.is_filetable = 0

select @SQL

--uncomment the line below to execute your dynamic sql
--exec sp_executesql @SQL

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

...