如何检测 table 是否是 SQL 服务器中的 FileTable

How to detect if a table is a FileTable in SQL Server

我正在使用现有的 SQL 脚本,该脚本会删除数据库中的所有外键。如果 table 之一是 FileTable,这就会遇到麻烦。

主要问题:有没有办法检测到特定 table 是 FILETABLE 并跳过删除那个 table 上的外键?

如果可能的话:是否也可以通过区分系统外键和自定义外键来获得更细粒度并从 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 的数据库上会导致类似

的错误

Msg 3865, Level 16, State 1, Line 3
The operation on object 'FK__DocumentS__paren__3A69DAC6' is blocked. The object is a FileTable system defined object and user modifications are not allowed.

Msg 3727, Level 16, State 0, Line 3
Could not drop constraint. See previous errors.

您不应该为此使用信息模式视图。特别是因为您关心架构。 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。使用像这样的未记录的过程很少是一个好主意。我也会有点紧张,因为您要关闭每个 table 上的所有约束,而不仅仅是您删除的约束。也许相反,您应该捕获所有要从中删除外键的 tables(在删除它们之前),然后仅禁用那些 tables 上的所有约束。