【发布时间】:2018-06-27 17:28:51
【问题描述】:
我们在继承的数据库中有大量视图,其中一些缺少依赖项(表甚至其他视图)?
识别缺少依赖项的视图的最佳方法是什么?
【问题讨论】:
标签: sql sql-server
我们在继承的数据库中有大量视图,其中一些缺少依赖项(表甚至其他视图)?
识别缺少依赖项的视图的最佳方法是什么?
【问题讨论】:
标签: sql sql-server
DECLARE @stmt nvarchar(max) = ''
DECLARE @vw_schema NVARCHAR(255)
DECLARE @vw_name varchar(255)
IF OBJECT_ID('tempdb..#badViews') IS NOT NULL DROP TABLE #badViews
IF OBJECT_ID('tempdb..#nulldata') IS NOT NULL DROP TABLE #nulldata
CREATE TABLE #badViews
(
[schema] NVARCHAR(255),
name VARCHAR(255),
error NVARCHAR(MAX)
)
CREATE TABLE #nullData
(
null_data varchar(1)
)
DECLARE tbl_cursor CURSOR LOCAL FORWARD_ONLY READ_ONLY
FOR SELECT name, SCHEMA_NAME(schema_id) AS [schema]
FROM sys.objects
WHERE type='v'
OPEN tbl_cursor
FETCH NEXT FROM tbl_cursor
INTO @vw_name, @vw_schema
WHILE @@FETCH_STATUS = 0
BEGIN
SET @stmt = 'SELECT TOP 1 * FROM [' + @vw_schema + N'].[' + @vw_name + ']'
BEGIN TRY
INSERT INTO #nullData EXECUTE sp_executesql @stmt
END TRY
BEGIN CATCH
IF ERROR_NUMBER() != 213 BEGIN
INSERT INTO #badViews (name, [schema], error) values (@vw_name, @vw_schema, ERROR_MESSAGE())
END
END CATCH
FETCH NEXT FROM tbl_cursor
INTO @vw_name, @vw_schema
END
CLOSE tbl_cursor -- free the memory
DEALLOCATE tbl_cursor
SELECT * FROM #badViews
DROP TABLE #badViews
DROP TABLE #nullData
2017 年更新
根据@robyaw 的回答更新了答案。
我还为 select 语句中的计算值修复了一个错误。当vwTest 包含像1/0 as [Col1] 这样的列时,SELECT TOP 1 NULL from vwTest 似乎不会引发错误,但SELECT TOP 1 * from vwTest 它确实会引发异常。
2018 年更新 修复名称中包含特殊字符的视图和/或架构的误报。感谢@LucasAyala
【讨论】:
SET @stmt = 'SELECT TOP 1 * FROM [' + @vw_schema + N'].[' + @vw_name + ']'
Adrian Iftode 的解决方案很好,但如果存在未与默认架构关联的视图,则会失败。以下是他的解决方案的修订版,它考虑了架构,同时还提供了针对每个失败视图的错误信息(在 SQL Server 2012 上测试):
DECLARE @stmt NVARCHAR(MAX) = '';
DECLARE @vw_schema NVARCHAR(255);
DECLARE @vw_name NVARCHAR(255);
CREATE TABLE #badViews
(
[schema] NVARCHAR(255)
, name NVARCHAR(255)
, error NVARCHAR(MAX)
);
CREATE TABLE #nullData
(
null_data VARCHAR(1)
);
DECLARE tbl_cursor CURSOR FORWARD_ONLY READ_ONLY
FOR
SELECT
SCHEMA_NAME(schema_id) AS [schema]
, name
FROM
sys.objects
WHERE
[type] = 'v';
OPEN tbl_cursor;
FETCH NEXT FROM tbl_cursor INTO @vw_schema, @vw_name;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @stmt = CONCAT(N'SELECT TOP 1 NULL FROM ', @vw_schema, N'.', @vw_name);
BEGIN TRY
-- silently execute the "select from view" query
INSERT INTO #nullData EXECUTE sp_executesql @stmt;
END TRY
BEGIN CATCH
INSERT INTO #badViews ([schema], name, error)
VALUES (@vw_schema, @vw_name, ERROR_MESSAGE());
END CATCH
FETCH NEXT FROM tbl_cursor INTO @vw_schema, @vw_name;
END
CLOSE tbl_cursor;
DEALLOCATE tbl_cursor;
-- print the views with errors when executed
SELECT * FROM #badViews;
DROP TABLE #badViews;
DROP TABLE #nullData;
【讨论】:
试试this
在所有非模式绑定的存储过程上调用 sp_refreshsqlmodule:
DECLARE @template AS varchar(max)
SET @template = 'PRINT ''{OBJECT_NAME}''
EXEC sp_refreshsqlmodule ''{OBJECT_NAME}''
'
DECLARE @sql AS varchar(max)
SELECT @sql = ISNULL(@sql, '') + REPLACE(@template, '{OBJECT_NAME}',
QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME))
FROM INFORMATION_SCHEMA.ROUTINES
WHERE OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') IS NULL
OR OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') = 0
EXEC (
@sql
)
这适用于所有视图、函数和 SP。 Schemabound 对象不会有问题,并且无法在它们上运行,这就是它们被排除在外的原因。
请注意,由于缺少表,SP 在运行时仍有可能失败 - 这相当于尝试 ALTER 过程。
另请注意,就像 ALTER 一样,它会丢失 UDF 上的扩展属性 - 我将这些属性关闭并在之后恢复它们。
【讨论】:
如果您使用的是 SQL Server 2005 或 2008,您可以将项目导入 Visual Studio 2008 或 2010 并分析 Visual Studio 项目中损坏的依赖项
【讨论】:
我会备份数据库,在我的开发机器上恢复它,在管理服务器的新窗口中创建一个包含所有视图的脚本,删除所有视图并尝试执行脚本。每当视图“损坏”时,执行将失败并显示错误消息,例如不存在表或列。
【讨论】: