【问题标题】:How to rebuild view in SQL Server 2008如何在 SQL Server 2008 中重建视图
【发布时间】:2010-12-06 03:55:34
【问题描述】:

我的数据库中有一个视图,有人用一个表中的 * 定义。我刚刚在该表中添加了一个新列,我希望视图能够反映新列。除了重新执行视图创建脚本之外,还有另一种重建视图的方法吗?我正在寻找类似于 sp_recompile 如何重新编译存储过程(或更准确地标记它以在下次调用时对其进行编译)。

更新:我尝试在视图上调用 sp_recompile,虽然调用有效,但它并没有重建视图。

更新 2:我希望能够从脚本中执行此操作。因此,将列添加到表中的脚本也可以更新视图。所以就像我说的,类似于 sp_recompile。

【问题讨论】:

  • 那么你的意图是什么?您是否尝试将首次访问延迟降至最低?
  • 视图没有反映表中的新列。我想强制视图包含新列。

标签: sql sql-server tsql sql-server-2008 view


【解决方案1】:

我相信你正在寻找的是

sp_refreshview [ @viewname = ] 'viewname'

更新指定的元数据 非模式绑定视图。执着的 视图的元数据可以变成 因更改而过时 视图所依据的基础对象 取决于。

See Microsoft Docs

【讨论】:

  • 很好,但我有一个问题,如果我的视图有多个表格,并且我添加的列会给我添加到视图中的冲突,那么会发生什么?
【解决方案2】:

为了重建 SQL Server 数据库的所有视图,您可以使用以下脚本:

DECLARE @view_name AS NVARCHAR(500);

DECLARE views_cursor CURSOR FOR 
    SELECT TABLE_SCHEMA + '.' +TABLE_NAME FROM INFORMATION_SCHEMA.TABLES 
    WHERE TABLE_TYPE = 'VIEW' 
    AND OBJECTPROPERTY(OBJECT_ID(TABLE_NAME), 'IsMsShipped') = 0 
    ORDER BY TABLE_SCHEMA,TABLE_NAME 

OPEN views_cursor 

FETCH NEXT FROM views_cursor 
INTO @view_name 

WHILE (@@FETCH_STATUS <> -1) 
BEGIN
    BEGIN TRY
        EXEC sp_refreshview @view_name;
        PRINT @view_name;
    END TRY
    BEGIN CATCH
        PRINT 'Error during refreshing view "' + @view_name + '".';
    END CATCH;

    FETCH NEXT FROM views_cursor 
    INTO @view_name 
END 

CLOSE views_cursor; 
DEALLOCATE views_cursor;

这是对this blog posting 稍作修改的版本。它也使用sp_refreshview stored procedure。

【讨论】:

  • 我的大多数视图都产生了这个脚本的错误(刷新视图“xxx”时出错。)即使视图是正确的,我也可以执行“SELECT * FROM xxx”。难道这个存储过程不能处理包含其他视图作为源“表”的视图?
【解决方案3】:

你可以使用这个sp:

CREATE PROCEDURE dbo.RefreshViews 
    @dbName nvarchar(100) = null 
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @p nvarchar(250) = '@sql nvarchar(max) out'
    DECLARE @q nvarchar(1000)
    DECLARE @sql nvarchar(max)

    if @dbName is null
        select @dbName = DB_NAME()

    SELECT @q = 'SELECT @sql = COALESCE(@sql + '' '', '''') + ''EXEC sp_refreshview ''''[' + @dbName + '].['' + TABLE_SCHEMA + ''].['' + TABLE_NAME + '']'''';'' 
                FROM [' + @dbName + '].INFORMATION_SCHEMA.Views  '

    EXEC sp_executesql @q , @p ,@sql out

    EXEC sp_executesql @sql     


END
GO

【讨论】:

    【解决方案4】:

    这是我最喜欢的脚本(我修改了一个旧的 sp_exec 检查脚本),它使用 EXEC sp_refreshsqlmodule @name

    SET NOCOUNT ON;
    
    -- Set ViewOnly to 1 to view missing EXECUTES. Set to 0 to correct missing EXECUTEs
    DECLARE
          @ViewOnly INT; SET @ViewOnly = 0;
    
    -- Role to set execute permission on.
    DECLARE 
          @ROLE  sysname ; set @ROLE = QUOTENAME('spexec');
    
    DECLARE 
          @ID      INT,
        @LAST_ID INT,
          @NAME NVARCHAR(2000),
          @SQL  NVARCHAR(2000);
    
    DECLARE @Permission TABLE (
          id INT IDENTITY(1,1) NOT NULL,
          spName  NVARCHAR(2000),
          object_type NVARCHAR(2000),
          roleName  NVARCHAR(2000),
          permission  NVARCHAR(2000),
          state  NVARCHAR(2000)
    )
    
    --Initialise the loop variable
    SET @LAST_ID = 0
    --Get all the stored procs into a temp table. 
    WHILE @LAST_ID IS NOT NULL
    BEGIN
        -- Get next lowest value
        SELECT @ID = MIN(object_id)
        FROM sys.objects 
        WHERE object_id > @LAST_ID  
          -- Looking for Stored Procs, Scalar, Table and Inline Functions
                AND type IN ('P','FN','IF','TF','AF','FS','FT','PC', 'V')
    
        SET @LAST_ID = @ID
    
        IF @ID IS NOT NULL
        BEGIN
                INSERT INTO @Permission
                SELECT o.name,
                      o.type_desc, 
                      r.name,  
                      p.permission_name,  
                      p.state_desc 
                FROM sys.objects AS o
                LEFT outer JOIN sys.database_permissions AS p
                      ON p.major_id = o.object_id
                LEFT OUTER join sys.database_principals r 
                      ON p.grantee_principal_id = r.principal_id
                WHERE o.object_id = @ID 
                      AND o.type IN ('P','FN','IF','TF','AF','FS','FT','PC', 'V')  
                      --Exclude special stored procs, which start with dt_...
                      AND NOT o.name LIKE 'dt_%'
                      AND NOT o.name LIKE 'sp_%'
                      AND NOT o.name LIKE 'fn_%'
          END   
    END
    
    --GRANT the Permissions, only if the viewonly is off.
    IF ISNULL(@ViewOnly,0) = 0 
    BEGIN
          --Initialise the loop variable
          SET @LAST_ID = 0
          WHILE @LAST_ID IS NOT NULL
          BEGIN
                -- Get next lowest value
                SELECT @ID = MIN(id)
                FROM @Permission 
                WHERE roleName IS NULL
                      AND id > @LAST_ID
    
                SET @LAST_ID = @ID
    
                IF @ID IS NOT NULL
                BEGIN
                      SELECT @NAME = spName
                      FROM @Permission 
                      WHERE id = @ID
    
                      PRINT 'EXEC sp_refreshsqlmodule ' + @NAME
                      -- Build the DCL to do the GRANT
                      SET @SQL = 'sp_refreshsqlmodule [' + @NAME + ']'
    
                      -- Run the SQL Statement you just generated
                      EXEC (@SQL)
                END
          END
    
          --Reselect the now changed permissions
          SELECT o.name,
                o.type_desc, 
                r.name,  
                p.permission_name,  
                p.state_desc 
          FROM sys.objects AS o
          LEFT outer JOIN sys.database_permissions AS p
                ON p.major_id = o.object_id
          LEFT OUTER join sys.database_principals r 
                ON p.grantee_principal_id = r.principal_id
          WHERE o.type IN ('P','FN','IF','TF','AF','FS','FT','PC', 'V') 
                AND NOT o.name LIKE 'dt_%'
                AND NOT o.name LIKE 'sp_%'
                AND NOT o.name LIKE 'fn_%'
          ORDER BY o.name
    END
    ELSE
    BEGIN
          --ViewOnly: select the stored procs which need EXECUTE permission.
          SELECT *
          FROM @Permission 
          WHERE roleName IS NULL
    END
    

    【讨论】:

      【解决方案5】:

      sp_refreshview 似乎不可靠!当我使用来自 Uwe Keim/BogdanRB 的代码时,即使视图没有无效引用,我也会遇到很多错误!以下代码对我有用(确定架构更改后哪个视图无效):

      DECLARE @view_name AS NVARCHAR(500);
      DECLARE @Query AS NVARCHAR(600);
      SET @Query = '';
      DECLARE views_cursor CURSOR FOR SELECT DISTINCT ('[' + SCHEMA_NAME(schema_id) + '].[' + name + ']') AS Name FROM sys.views
      OPEN views_cursor 
      
      FETCH NEXT FROM views_cursor 
      INTO @view_name 
      
      WHILE (@@FETCH_STATUS <> -1) 
      BEGIN
              EXEC sp_recompile @view_name;
              SELECT @Query = 'SELECT ''' + @view_name + ''' AS Name, COUNT(*) FROM ' + @view_name + ' AS Count; ';
              EXEC (@Query);
              -- PRINT @view_name;
      
          FETCH NEXT FROM views_cursor 
          INTO @view_name 
      END 
      
      CLOSE views_cursor; 
      DEALLOCATE views_cursor;
      

      【讨论】:

        【解决方案6】:

        稍作修改的脚本,刷新所有视图,调用 sp_recompile、sp_refresh 并从 sys.views 获取列表:

        DECLARE @view_name AS NVARCHAR(500);
        DECLARE views_cursor CURSOR FOR SELECT DISTINCT name from sys.views
        OPEN views_cursor 
        
        FETCH NEXT FROM views_cursor 
        INTO @view_name 
        
        WHILE (@@FETCH_STATUS <> -1) 
        BEGIN
            BEGIN TRY
                EXEC sp_recompile @view_name;
                EXEC sp_refreshview @view_name;
                PRINT @view_name;
            END TRY
            BEGIN CATCH
                PRINT 'Error during refreshing view "' + @view_name + '".';
            END CATCH;
        
            FETCH NEXT FROM views_cursor 
            INTO @view_name 
        END 
        
        CLOSE views_cursor; 
        DEALLOCATE views_cursor;
        

        【讨论】:

          【解决方案7】:

          除了 Cory 的回答,您还可以使用架构绑定和完整的列列表正确定义它。

          CREATE VIEW MyView
          WITH SCHEMABINDING
          AS
          SELECT
              col1, col2, col3, ..., coln
          FROM
              MyTable
          GO
          

          【讨论】:

            【解决方案8】:

            右键单击视图并从弹出菜单中选择刷新?

            【讨论】:

            • 我希望能够从脚本中执行此操作。因此,将列添加到表中的脚本也可以更新视图。所以就像我说的,类似于 sp_recompile。
            猜你喜欢
            • 1970-01-01
            • 2012-02-15
            • 2014-01-20
            • 2010-12-08
            • 2011-08-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-11-09
            相关资源
            最近更新 更多