【问题标题】:How do I identify views with broken dependencies in SQL Server?如何识别 SQL Server 中依赖项损坏的视图?
【发布时间】:2018-06-27 17:28:51
【问题描述】:

我们在继承的数据库中有大量视图,其中一些缺少依赖项(表甚至其他视图)?

识别缺少依赖项的视图的最佳方法是什么?

【问题讨论】:

标签: sql sql-server


【解决方案1】:
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

【讨论】:

  • 我建议将 sp_sqlexec 更改为 sp_executesql。为什么?它在 SQL Server 2000 SP3 中已被弃用。虽然它可能在您当前的版本中仍然有效,但在您升级甚至应用下一个 Service Pack 时它可能会停止工作。向下滚动到最后第三项:msdn.microsoft.com/en-us/site/aa215533
  • 我会添加括号引用视图名称以避免误报包含空格或标点符号的视图SET @stmt = 'SELECT TOP 1 * FROM [' + @vw_schema + N'].[' + @vw_name + ']'
【解决方案2】:

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;

【讨论】:

    【解决方案3】:

    试试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 上的扩展属性 - 我将这些属性关闭并在之后恢复它们。

    【讨论】:

    • Cade,只是好奇你是否在一个有多个对象破坏依赖关系的环境中尝试过这个?当我尝试类似的事情时遇到了这个错误:connect.microsoft.com/SQLServer/feedback/details/678806
    • @Aaron Bertand - 不,这不是我真正尝试自动化的操作,我只是用代码生成了类似于上面的脚本并偶尔查看结果。如果您尝试非常主动地对此进行监控,这似乎是一个非常有问题的错误。
    【解决方案4】:

    如果您使用的是 SQL Server 2005 或 2008,您可以将项目导入 Visual Studio 2008 或 2010 并分析 Visual Studio 项目中损坏的依赖项

    【讨论】:

      【解决方案5】:

      我会备份数据库,在我的开发机器上恢复它,在管理服务器的新窗口中创建一个包含所有视图的脚本,删除所有视图并尝试执行脚本。每当视图“损坏”时,执行将失败并显示错误消息,例如不存在表或列。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-03-27
        • 2010-09-22
        • 2021-04-21
        • 2011-12-30
        • 2015-05-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多