2009-10-12 20 views
25

Hay una vista en mi base de datos que alguien definió con * desde una tabla. Acabo de agregar una nueva columna a esa tabla y quiero que la vista refleje la nueva columna. Además de volver a ejecutar el script de creación de vista, ¿hay alguna otra manera de reconstruir la vista? Estoy buscando algo similar a cómo sp_recompile recompilará un procedimiento almacenado (o más exactamente lo marcará para que se compile la próxima vez que se llame).Cómo reconstruir vista en SQL Server 2008

Actualización: En una oportunidad, traté de llamar a sp_recompile en la vista y mientras la llamada funcionaba, no volvió a generar la vista.

Actualización 2: Me gustaría poder hacer esto desde un script. Entonces, la secuencia de comandos que agrega las columnas a la tabla también podría actualizar la vista. Así que como dije, algo similar a sp_recompile.

+0

Entonces, ¿cuál es tu intención? ¿Estás tratando de minimizar el retraso en el acceso por primera vez? – Sung

+1

La vista no refleja las nuevas columnas en la tabla. Quiero forzar la vista para incluir las nuevas columnas. –

Respuesta

39

creo que lo que estás buscando es

sp_refreshview [ @viewname = ] 'viewname' 

actualiza los metadatos para el vista no unido a esquema especificado. Los metadatos persistentes para una vista pueden convertirse en obsoletos debido a cambios en los objetos subyacentes de los que depende la vista .

http://technet.microsoft.com/en-us/library/ms187821.aspx

+0

Eso hizo el truco. ¡Gracias! –

+0

Es bueno, pero tengo una pregunta, si mi vista tiene más de tabla y agrego una columna que me dará conflictos al agregar a la vista, ¿qué ocurre? – KuldipMCA

0

¿Hace clic derecho en la vista y elige Actualizar en el menú emergente?

+1

Me gustaría poder hacer esto desde un script. Entonces, la secuencia de comandos que agrega las columnas a la tabla también podría actualizar la vista. Así que como dije, algo similar a sp_recompile. –

5

Así como la respuesta de Cory, se podría definir de forma adecuada utilizando SCHEMABINDING y la lista de la columna completa.

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

Con el fin de reconstruir todos los vistas de una base de datos SQL Server, puede utilizar el siguiente script:

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; 

Ésta es una versión ligeramente modificada de this blog posting. Utiliza el sp_refreshview stored procedure, también.

+1

La mayoría de mis vistas producen un error con este script (Error durante la actualización de la vista "xxx"). Incluso cuando la vista es correcta y puedo realizar un "SELECT * FROM xxx". ¿Podría ser que este procedimiento almacenado no pueda manejar vistas que incluyen otras vistas como "tablas" de origen? – Christoph

2

guión ligeramente modificada que refresca todas las vistas, llama sp_recompile, sp_refresh y la lista obtiene de 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; 
2

sp_refreshview no parece ser relyable! Cuando utilicé el código de Uwe Keim/BogdanRB recibí muchos errores incluso si la vista no tiene referencias inválidas. El código siguiente hizo el truco para mí (para determinar qué punto de vista no es válido después de los cambios de esquema):

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; 
1

Aquí está mi script favorito para esto (he modificado un viejo guión de cheques sp_exec que tenía), que utiliza sp_refreshsqlmodule EXEC @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 
0

Se puede usar esta 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