第六章 SQL定義和使用視圖
視圖是一種虛擬表,由執行時通過SELECT
語句或幾個SELECT
語句的UNION
從一個或多個物理表中檢索到的數據組成。 SELECT
可以通過指定表或其他視圖的任意組合來訪問數據。因此,存儲了視圖的視圖提供了物理表的所有靈活性和安全性特權。
InterSystemsIRIS?數據平臺上的InterSystems SQL支持在視圖上定義和執行查詢的功能。
注意:不能對以只讀方式安裝的數據庫中存儲的數據創建視圖。
無法在通過ODBC或JDBC網關連接鏈接的Informix
表中存儲的數據上創建視圖。這是因為InterSystems IRIS查詢轉換對這種類型的查詢使用FROM子句中的子查詢。 Informix
不支持FROM
子句子查詢。
創建一個視圖
可以通過幾種方式定義視圖:
- 使用SQL
CREATE VIEW
命令(在DDL腳本中或通過JDBC或ODBC)。 - 使用管理門戶的“創建視圖”界面。
視圖名稱:不合格的視圖名稱是一個簡單的標識符:MyView
。合格的視圖名稱由兩個簡單的標識符組成,即模式名稱和視圖名稱,以句點分隔:MySchema.MyView
。視圖名稱和表名稱遵循相同的命名約定,并對不合格的名稱執行相同的架構名稱解析。同一模式中的視圖和表不能具有相同的名稱。
可以使用$SYSTEM.SQL.ViewExists()
方法確定視圖名稱是否已存在。此方法還返回投影視圖的類名稱。可以使用$SYSTEM.SQL.TableExists()
方法確定表名是否已存在。
視圖可用于創建表的受限子集。以下嵌入式SQL示例創建一個視圖,該視圖限制了可以通過該視圖訪問的原始表的行(通過WHERE
子句)和列(假設Sample.Person
包含兩個以上的列):
/// d ##class(PHA.TEST.SQL).View()
ClassMethod View()
{
&sql(CREATE VIEW Sample.VSrStaff
AS SELECT Name AS Vname,Age AS Vage
FROM Sample.Person WHERE Age>75)
IF SQLCODE=0 {
WRITE "創建一個視圖",!
} ELSEIF SQLCODE=-201 {
WRITE "視圖已經存在",!
} ELSE {
WRITE "SQL報錯: ",SQLCODE," ",%msg,!
}
}
DHC-APP>d ##class(PHA.TEST.SQL).View()
創建一個視圖
以下嵌入式SQL示例基于SalesPeople
表創建一個視圖,并創建一個新的計算值列TotalPay
:
/// d ##class(PHA.TEST.SQL).View1()
ClassMethod View1()
{
&sql(CREATE VIEW Sample.VSalesPay AS
SELECT Name,(Salary + Commission) AS TotalPay
FROM Sample.SalesPeople)
IF SQLCODE=0 {
WRITE "創建一個視圖",!
} ELSEIF SQLCODE=-201 {
WRITE "視圖已經存在",!
} ELSE {
WRITE "SQL報錯: ",SQLCODE," ",%msg,!
}
}
管理門戶創建視圖界面
可以從管理門戶創建視圖。轉到InterSystems IRIS管理門戶。在系統資源管理器中,選擇SQL。使用頁面頂部的Switch選項選擇一個名稱空間;這將顯示可用名稱空間的列表。選擇名稱空間后,單擊“操作”下拉列表,然后選擇“創建視圖”。
這將顯示“創建視圖”窗口,其中包含以下字段:
- 模式:可以決定將視圖包含在現有模式中,也可以創建一個新模式。如果選擇選擇現有模式,則會提供一個現有模式的下拉列表。如果選擇創建新架構,請輸入架構名稱。在這兩種情況下,如果省略模式,則InterSystems IRIS都會使用系統范圍內的默認模式名稱。
- 視圖名稱:有效的視圖名稱。不能對同一模式中的表和視圖使用相同的名稱。
- 使用
Check Option
:選項為READONLY
,LOCAL
,CASCADED
。 - 將視圖的所有特權授予
_PUBLIC
:如果選中,則此選項為該視圖授予所有用戶執行特權。默認設置是不授予所有用戶訪問該視圖的權限。 - 查看文字:可以通過以下三種方式中的任意一種來指定查看文字:
- 在“查看文本”區域中鍵入SELECT語句。
- 使用查詢生成器創建
SELECT
語句,然后按OK將此查詢提供給“查看文本”區域。 - 如果在Management Portal SQL界面的左側選擇了一個緩存查詢名稱(例如
%sqlcq.USER.cls4
),然后調用Create View
,則該緩存查詢將提供給“視圖文本”區域。請注意,在保存視圖文本之前,必須在“視圖文本”區域中用實際值替換主機變量引用。
視圖和相應的類
定義視圖時,InterSystems IRIS會生成一個相應的類。按照名稱轉換規則,SQL視圖名稱用于生成相應的唯一類名稱。 Management Portal SQL界面顯示現有視圖的“目錄詳細信息”,包括此類名稱。
修改視圖
在Management Portal SQL界面中,可以選擇一個現有視圖以顯示該視圖的“目錄詳細信息”。 “目錄詳細信息視圖信息”選項顯示“編輯視圖”鏈接,該鏈接提供了用于編輯視圖文本(視圖的SELECT
語句)的界面。它還提供了一個下拉列表,以將“帶檢查選項”選擇為無,READONLY
,LOCAL
或CASCADED
。
可更新的視圖
可更新的視圖是可以在其上執行INSERT
,UPDATE
和DELETE
操作的視圖。僅當滿足以下條件時,才認為視圖是可更新的:
- 視圖查詢的
FROM
子句僅包含一個表引用。該表引用必須標識可更新的基表或可更新的視圖。 - 視圖查詢的
SELECT
列表中的值表達式必須全部是列引用。 - 視圖的查詢中不得指定
GROUP BY
,HAVING
或SELECT DISTINCT
。 - 該視圖不是投影為視圖的類查詢。
- 視圖的類不包含類參數
READONLY = 1
(如果視圖定義包含WITH READ ONLY
子句,則為true
)。
WITH CHECK選項
為了防止在視圖上執行INSERT
或UPDATE
操作,而該操作會導致基礎基表中的行不屬于派生視圖表的一部分,InterSystems SQL在視圖定義中支持WITH CHECK OPTION
子句。此子句只能與可更新視圖一起使用。
WITH CHECK OPTION
子句指定可更新視圖上的任何INSERT
或UPDATE
操作必須對照視圖定義的WHERE子句驗證結果行,以確保插入或修改的行將成為派生視圖表的一部分。
例如,以下DDL語句定義了一個可更新的GoodStudent
視圖,其中包含所有具有高GPA
(平均績點)的學生:
CREATE VIEW GoodStudent AS
SELECT Name, GPA
FROM Student
WHERE GPA > 3.0
WITH CHECK OPTION
由于視圖包含WITH CHECK OPTION
,因此任何嘗試在GPA
值小于或等于3.0的GoodStudent
視圖中插入或更新行都將失敗(此類行將不表示“好學生”)。
有兩種類型的WITH CHECK
選項:
-
WITH LOCAL CHECK
選項意味著只檢查INSERT
或UPDATE
語句中指定的視圖的WHERE
子句。 - 與級聯檢查選項(和級聯檢查選項)意味著視圖的
WHERE
子句中指定的INSERT
或UPDATE
語句以及所有視圖檢查基于這一觀點,無論外表或與當地檢查沒有其他選項在這些視圖定義條款。
如果指定了just WITH CHECK
選項,默認值是級聯的。
在更新或插入期間,在為基礎表的字段計算了所有默認值和觸發的計算字段之后,并在常規表驗證(必需字段、數據類型驗證、約束等)之前,檢查WITH CHECK
選項條件。
在WITH CHECK
選項驗證通過后,插入或更新操作繼續進行,就像在基表本身上執行插入或更新一樣。
檢查所有約束,拉出觸發器,等等。
如果在INSERT
或UPDATE
語句中指定了%NOCHECK
選項,則不檢查WITH CHECK
選項的有效性。
有兩個與WITH CHECK
選項驗證相關的SQLCODE
值(插入/更新會導致派生視圖表中不存在一行):
-
SQLCODE -136
-INSERT
中視圖的WITH CHECK OPTION
驗證失敗。 -
SQLCODE -137
-視圖的WITH CHECK OPTION
驗證在UPDATE
中失敗。
只讀視圖
只讀視圖是不能在其上執行INSERT
,UPDATE
和DELETE
操作的視圖。任何不符合可更新視圖標準的視圖都是只讀視圖。
視圖定義可以指定WITH READ ONLY
子句,以強制其成為只讀視圖。
如果嘗試針對只讀視圖編譯/準備INSERT
,UPDATE
或DELETE
語句,則會生成SQLCODE -35
錯誤。
查看ID:%VID
InterSystems IRIS為視圖或FROM
子句子查詢返回的每一行分配一個整數視圖ID
(%VID
)。與表行ID
號一樣,這些視圖行ID
號是系統分配的,唯一的,非空的,非零的和不可修改的。該%VID
通常對用戶不可見,并且僅在明確指定時返回。它以數據類型INTEGER
返回。因為%VID
值是順序整數,所以如果視圖返回有序數據,它們將更有意義。視圖與TOP子句配對時,只能使用ORDER BY
子句。以下嵌入式SQL示例創建一個名為VSrStaff
的視圖:
/// d ##class(PHA.TEST.SQL).View()
ClassMethod View()
{
&sql(CREATE VIEW Sample.VSrStaff
AS SELECT Name AS Vname,Age AS Vage
FROM Sample.Person WHERE Age>75)
IF SQLCODE=0 {
WRITE "創建一個視圖",!
} ELSEIF SQLCODE=-201 {
WRITE "視圖已經存在",!
} ELSE {
WRITE "SQL報錯: ",SQLCODE," ",%msg,!
}
}
下面的示例返回VSrStaff
視圖定義的所有數據(使用SELECT *
),并且還指定應返回每一行的視圖ID
。與表行ID
不同,使用星號語法時不顯示視圖行ID
。僅當在SELECT
中明確指定時才顯示:
SELECT *,%VID AS ViewID FROM Sample.VSrStaff
%VID
可用于進一步限制SELECT
從視圖返回的行數,如以下示例所示:
SELECT *,%VID AS ViewID FROM Sample.VSrStaff WHERE %VID BETWEEN 5 AND 10
因此,可以使用%VID
代替TOP
(或除TOP
之外)來限制查詢返回的行數。通常,TOP
子句用于返回數據記錄的一小部分。 %VID
用于返回大多數或所有數據記錄,以小的子集返回記錄。此功能可能很有用,尤其是對于移植Oracle查詢(%VID
輕松映射到Oracle ROWNUM)而言。但是,與TOP
相比,用戶應了解使用%VID
時的一些性能限制:
-
%VID
不執行第一行時間優化。TOP
優化為盡快返回第一行數據。%VID
優化以盡快返回完整的數據集。 - 如果查詢指定排序的結果,則
%VID
不會執行有限的排序(這是TOP
進行的特殊優化)。該查詢首先對完整的數據集進行排序,然后使用%VID
限制返回數據集。TOP
是在排序之前應用的,因此SELECT
只能執行有限的排序,僅涉及有限的行子集。
為了節省第一行優化和有限排序優化的時間,可以將FROM
子句子查詢與TOP
和%VID
結合使用。在FROM
子查詢中指定上限(在本例中為10)作為TOP
的值,而不是使用TOP ALL
。使用%VID
在WHERE
子句中指定下限(在這種情況下,> 4
)。以下示例使用此策略返回與上一個視圖查詢相同的結果:
SELECT *,%VID AS SubQueryID
FROM (SELECT TOP 10 Name,Age
FROM Sample.Person
WHERE Age > 75
ORDER BY Name)
WHERE %VID > 4
即使顯式指定了%PARALLEL
關鍵字,也無法對指定%VID
的查詢執行并行執行。
List視圖屬性
INFORMATION.SCHEMA.VIEWS
持久類顯示有關當前名稱空間中所有視圖的信息。它提供了許多屬性,包括視圖定義,視圖的所有者以及創建和最后修改視圖時的時間戳。這些屬性還包括視圖是否可更新,如果可更新,是否使用檢查選項定義。
在嵌入式SQL中指定時,INFORMATION.SCHEMA.VIEWS
需要#include%occInclude
宏預處理程序指令。 Dynamic SQL
不需要此偽指令。
VIEWDEFINITION
屬性(SqlFieldName = VIEW_DEFINITION
)以字符串形式返回當前名稱空間中所有視圖的視圖字段名稱和視圖查詢表達式。例如,
SELECT View_Definition FROM INFORMATION_SCHEMA.VIEWS
返回諸如“(vName,vAge)SELECT Name,Age FROM Sample.Person WHERE Age> 21”
的字符串。當從Management Portal SQL執行查詢界面發出時,此字符串的顯示僅限于前100個字符,其中不包括空格和換行符,并且(如有必要)附加表示省略號的省略號(...
)。否則,發出此查詢將為每個視圖返回最多1048576
個字符的字符串,在視圖字段列表和查詢文本之間有一個換行符,并保留了視圖查詢表達式中指定的空格,并(如有必要)附加了省略號(...
)表示內容被截斷。
以下示例返回當前名稱空間中所有視圖的視圖名稱(Table_Name字段)和所有者名稱:
SELECT Table_Name,Owner FROM INFORMATION_SCHEMA.VIEWS
以下示例返回當前名稱空間中所有非系統視圖的所有信息:
SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE Owner != '_SYSTEM'
INFORMATION.SCHEMA.VIEWCOLUMNUSAGE
持久性類顯示當前名稱空間中每個視圖的源表字段的名稱:
SELECT * FROM INFORMATION_SCHEMA.VIEW_COLUMN_USAGE WHERE View_Name='VSrStaff'
可以使用管理門戶網站SQL界面中的“目錄詳細信息”選項卡為單個視圖顯示與INFORMATION.SCHEMA.VIEWS
相同的信息。視圖的“目錄詳細信息”包括每個視圖字段的定義(數據類型,最大長度,最小值/最大值等),以及INFORMATION.SCHEMA
視圖類未提供的詳細信息。 “目錄詳細信息”視圖信息顯示還提供了用于編輯視圖定義的選項。
列出視圖依賴
INFORMATION.SCHEMA.VIEWTABLEUSAGE
持久類顯示當前名稱空間中的所有視圖及其依賴的表。在下面的示例中顯示:
SELECT View_Schema,View_Name,Table_Schema,Table_Name FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE
可以調用%Library.SQLCatalog.SQLViewDependsOn
類查詢以列出指定視圖所依賴的表。可以為此類查詢指定schema.viewname
。如果僅指定視圖名稱,則它將使用系統范圍的默認架構名稱。調用者必須具有指定視圖的特權才能執行此類查詢。在下面的示例中顯示:
/// d ##class(PHA.TEST.SQL).View3()
ClassMethod View3()
{
SET statemt=##class(%SQL.Statement).%New()
SET cqStatus=statemt.%PrepareClassQuery("%Library.SQLCatalog","SQLViewDependsOn")
IF cqStatus'=1 {
WRITE "%PrepareClassQuery failed:" DO $System.Status.DisplayError(cqStatus) QUIT
}
SET rset=statemt.%Execute("vschema.vname")
DO rset.%Display()
}
DHC-APP>d ##class(PHA.TEST.SQL).View3()
Dumping result #1
SCHEMA TABLE_NAME
0 Rows(s) Affected
此SQLViewDependsOn
查詢列出了視圖所依賴的表,并列出了表架構和表名。如果調用者沒有該視圖所依賴的表的特權,則該表及其模式將列為<NOT PRIVILEGED>
。這允許沒有表特權的調用者確定視圖所依賴的表數量,而不是表的名稱。