私のDBには、誰かが1つのテーブルの*で定義したというビューがあります。そのテーブルに新しい列を追加したばかりで、ビューに新しい列を反映させたいと思います。ビュー作成スクリプトを再実行する以外に、ビューを再構築する別の方法はありますか? sp_recompileがストアドプロシージャを再コンパイルする(または、次に呼び出されたときにコンパイルされるように、より正確にフラグを立てる)方法に似たものを探しています。
更新:ロングショットで、ビューでsp_recompileを呼び出そうとしましたが、呼び出しが機能している間、ビューが再構築されませんでした。
更新2:スクリプトからこれを実行できるようにしたいと思います。したがって、列をテーブルに追加するスクリプトもビューを更新できます。だから私が言ったように、sp_recompileに似たもの。
あなたが探しているのは
sp_refreshview [ @viewname = ] 'viewname'
指定された非スキーマバインドビューのメタデータを更新します。ビューが依存する基になるオブジェクトが変更されたため、ビューの永続的なメタデータが古くなる可能性があります。
SQL Serverデータベースのallビューを再構築するには、次のスクリプトを使用できます。
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;
これは このブログ投稿 から少し変更されたバージョンです。 sp_refreshview
ストアドプロシージャ も。
Coryの答えと同様に、スキーマバインディングと完全な列リストを使用して適切に定義できます。
CREATE VIEW MyView
WITH SCHEMABINDING
AS
SELECT
col1, col2, col3, ..., coln
FROM
MyTable
GO
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;
すべてのビューを更新し、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;
これが私のお気に入りのスクリプトです(古いsp_execチェックスクリプトを変更しました)。EXECsp_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
この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
ビューを右クリックして、ポップアップメニューから[更新]を選択しますか?