如何避免修改基底資料表的結構後,造成檢視(View)無法使用

本文將介紹修改檢視的基底資料表後應該怎麼做才可以讓檢視不會因此而無法使用。

我們可以在 SQL Server 中把複雜的查詢利用建立檢視(View)的方式來組合一個虛擬資料表,檢視之中所使用到的實際資料表可稱之為基底資料表,在 Database Engine 中並不會真正儲存檢視中的資料,而是儲存這些基底資料表的 metadata ,當您修改基底資料表的結構時,檢視的 metadata 並不會跟著更新,因而造成例外發生。

  • 下列程式碼示範在 Northwind 資料庫的 Region 資料表中新增一個 memo 欄位(第4-7列),接著以 Region 資料表為基底資料表,建立 v_Region 檢視,並故意利用第 20 列的 sp_renew 預存程序修改欄位名稱。

 

   1:  use Northwind
   2:  go
   3:   
   4:  --於Region資料表中新增一Memo欄位
   5:  alter table Region
   6:  add memo nvarchar(10)
   7:  go
   8:   
   9:  --建立View
  10:  if exists (select * from sys.views where name='v_Region')
  11:      drop view v_Region
  12:  go
  13:   
  14:  create view v_region
  15:  as
  16:  select RegionID,RegionDescription,Memo
  17:  from Region
  18:  go
  19:   
  20:  --將Memo改為PS
  21:  EXECUTE sp_rename N'dbo.Region.memo', N'PS', 'COLUMN' 
  22:  go
  23:   
  24:  select *
  25:  from v_region
  

當執行上述程式碼的第 24-25 列就會發生如下圖的錯誤訊息:

 

 

image

 

這個問題看起來簡單但卻容易被忽略,因此為避免修改資料表結構之後影響檢視,建議可以在修改基底資料表之後,利用下列程式碼來找出相依的檢視。

 

   1:  select distinct 'EXEC sp_refreshview ''' + name + ''''
   2:  from sys.objects AS so 
   3:  inner join sys.sql_expression_dependencies AS sed 
   4:      on so.object_id = sed.referencing_id 
   5:  where so.type = 'V' 
   6:  and sed.referenced_id = OBJECT_ID('Region')

 

 

或是可以在建立檢視之前利用 SCHEMABINDING 來避免檢視的基底資料表被修改,如下列的程式碼。

 

   1:  --建立View
   2:  if exists (select * from sys.views where name='v_Region')
   3:      drop view v_Region
   4:  go
   5:   
   6:  create view v_region
   7:  with schemabinding
   8:  as
   9:  select RegionID,RegionDescription,memo
  10:  from dbo.Region
  11:  go

 

【參考資料】