如何检测 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 上的所有约束。
我正在使用现有的 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 上的所有约束。