支援的版本:目前 (17) / 16 / 15 / 14 / 13
開發版本:devel
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2 / 7.1

CREATE VIEW

CREATE VIEW — 定義一個新的視窗

概要

CREATE [ OR REPLACE ] [ TEMP | TEMPORARY ] [ RECURSIVE ] VIEW name [ ( column_name [, ...] ) ]
    [ WITH ( view_option_name [= view_option_value] [, ... ] ) ]
    AS query
    [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]

描述

CREATE VIEW 定義一個查詢的視窗。這個視窗並不會實際實體化。反之,每次在查詢中參照到該視窗時,都會執行該查詢。

CREATE OR REPLACE VIEW 與之相似,但如果已存在同名的視窗,則會被取代。新的查詢必須產生與現有視窗查詢相同的欄位(也就是說,欄位名稱相同、順序相同,且資料類型相同),但可以在列表的末尾新增額外的欄位。產生輸出欄位的計算方式可能完全不同。

如果給定了結構描述名稱(例如,CREATE VIEW myschema.myview ...),則會在指定的結構描述中建立視窗。否則,它會在目前的結構描述中建立。臨時視窗存在於特殊的結構描述中,因此在建立臨時視窗時,不能給定結構描述名稱。視窗的名稱必須與同一個結構描述中的任何其他關係(表格、序列、索引、視窗、實體化視窗或外部表格)的名稱不同。

參數

TEMPORARYTEMP

如果指定,則視窗會建立為臨時視窗。臨時視窗會在目前工作階段結束時自動刪除。在臨時視窗存在期間,除非使用結構描述限定名稱參照,否則目前的連線無法看到同名的現有永久關係。

如果視窗參照的任何表格是臨時的,則視窗會建立為臨時視窗(無論是否指定 TEMPORARY)。

RECURSIVE

建立遞迴視窗。語法

CREATE RECURSIVE VIEW [ schema . ] view_name (column_names) AS SELECT ...;

等同於

CREATE VIEW [ schema . ] view_name AS WITH RECURSIVE view_name (column_names) AS (SELECT ...) SELECT column_names FROM view_name;

必須為遞迴視窗指定視窗欄位名稱清單。

名稱

要建立的視窗的名稱(可選擇性地使用結構描述限定)。

column_name

要用於視窗欄位的名稱的可選清單。如果未給定,則欄位名稱會從查詢中推斷。

WITH ( view_option_name [= view_option_value] [, ... ] )

此子句指定視窗的可選參數;支援下列參數

check_option (enum)

此參數可以是 localcascaded,相當於指定 WITH [ CASCADED | LOCAL ] CHECK OPTION(請參閱下文)。

security_barrier (boolean)

如果視窗的目的是提供列級安全性,則應使用此選項。有關完整詳細資料,請參閱第 39.5 節

security_invoker (boolean)

此選項會導致根據視窗使用者的權限(而非視窗擁有者的權限)來檢查底層基本關係。有關完整詳細資料,請參閱以下注意事項。

可以使用ALTER VIEW來更改現有視窗上的所有上述選項。

查詢

一個SELECTVALUES指令,它將提供視窗的欄位和列。

WITH [ CASCADED | LOCAL ] CHECK OPTION

此選項控制自動可更新視窗的行為。指定此選項後,將檢查視窗上的INSERTUPDATEMERGE指令,以確保新列滿足視窗定義條件(也就是說,檢查新列以確保它們通過視窗可見)。如果不是,則更新將被拒絕。如果未指定CHECK OPTION,則允許視窗上的INSERTUPDATEMERGE指令建立通過視窗不可見的列。支援下列檢查選項

LOCAL

僅針對直接在視窗本身中定義的條件檢查新列。不會檢查在底層基本視窗上定義的任何條件(除非它們也指定CHECK OPTION)。

CASCADED

新資料列會根據檢視及其所有底層基礎檢視的條件進行檢查。如果指定了 CHECK OPTION,且未指定 LOCALCASCADED,則預設為 CASCADED

CHECK OPTION 不能與 RECURSIVE 檢視一起使用。

請注意,CHECK OPTION 僅支援在自動可更新的檢視上使用,且這些檢視不能具有 INSTEAD OF 觸發器或 INSTEAD 規則。如果自動可更新的檢視定義在具有 INSTEAD OF 觸發器的基礎檢視之上,則可以使用 LOCAL CHECK OPTION 來檢查自動可更新檢視的條件,但不會檢查具有 INSTEAD OF 觸發器的基礎檢視的條件(串聯檢查選項不會串聯到可觸發器更新的檢視,並且任何直接在可觸發器更新的檢視上定義的檢查選項都將被忽略)。如果檢視或其任何基礎關聯具有 INSTEAD 規則,該規則導致 INSERTUPDATE 命令被重寫,則所有檢查選項都將在重寫的查詢中被忽略,包括從定義在具有 INSTEAD 規則的關聯之上的自動可更新檢視中的任何檢查。MERGE 在檢視或其任何基礎關聯具有規則時不被支援。

注意事項

使用 DROP VIEW 語句來刪除檢視。

請小心檢視的欄位名稱和類型是否按照您想要的方式賦予。例如

CREATE VIEW vista AS SELECT 'Hello World';

是不好的形式,因為欄位名稱預設為 ?column?;此外,欄位資料類型預設為 text,這可能不是您想要的。在檢視結果中使用字串常值的更好風格是類似於

CREATE VIEW vista AS SELECT text 'Hello World' AS hello;

預設情況下,對檢視中引用的底層基礎關聯的存取權限由檢視擁有者的權限決定。在某些情況下,這可用於提供對底層表格的安全但受限制的存取。但是,並非所有檢視都能防止篡改;請參閱 Section 39.5 以取得詳細資訊。

如果檢視的 security_invoker 屬性設定為 true,則對底層基礎關聯的存取權限由執行查詢的使用者的權限決定,而不是檢視擁有者。因此,安全呼叫者檢視的使用者必須對檢視及其底層基礎關聯具有相關的權限。

如果任何底層基礎關聯是安全呼叫者檢視,則它將被視為直接從原始查詢存取。因此,安全呼叫者檢視將始終使用目前使用者的權限檢查其底層基礎關聯,即使它是從沒有 security_invoker 屬性的檢視存取也是如此。

如果任何底層基礎關聯啟用了 資料列層級安全策略,那麼預設情況下,將應用檢視擁有者的資料列層級安全策略,並且存取這些策略引用的任何其他關聯,將由檢視擁有者的權限決定。但是,如果檢視的 security_invoker 設定為 true,那麼將使用調用使用者的策略和權限,就好像基礎關聯已直接從使用該檢視的查詢中引用一樣。

在檢視中呼叫的函數的處理方式與直接從使用檢視的查詢中呼叫它們的處理方式相同。因此,檢視的使用者必須具有呼叫檢視使用的所有函數的權限。檢視中的函數以執行查詢的使用者或函數擁有者的權限執行,取決於函數是否定義為 SECURITY INVOKERSECURITY DEFINER。因此,例如,直接在檢視中呼叫 CURRENT_USER 將始終傳回調用使用者,而不是檢視擁有者。這不受檢視的 security_invoker 設定的影響,因此將 security_invoker 設定為 false 的檢視 等同於 SECURITY DEFINER 函數,並且不應將這些概念混淆。

建立或替換檢視的使用者必須具有對檢視查詢中引用的任何綱要的 USAGE 權限,以便在這些綱要中查找引用的物件。但是,請注意,此查找僅在建立或替換檢視時發生。因此,檢視的使用者僅需要在包含檢視的綱要上擁有 USAGE 權限,而不需要在檢視查詢中引用的綱要上擁有該權限,即使對於安全呼叫者檢視也是如此。

當對現有檢視使用 CREATE OR REPLACE VIEW 時,只會變更檢視的定義 SELECT 規則,加上任何 WITH ( ... ) 參數及其 CHECK OPTION。其他檢視屬性,包括所有權、權限和非 SELECT 規則,保持不變。您必須擁有該檢視才能替換它(這包括成為擁有角色的成員)。

可更新的檢視

簡單檢視是自動可更新的:系統將允許在檢視上使用 INSERTUPDATEDELETEMERGE 語句,就像在普通表格上一樣。如果檢視滿足以下所有條件,則該檢視是自動可更新的

  • 檢視在其 FROM 列表中必須恰好有一個條目,該條目必須是表格或另一個可更新的檢視。

  • 檢視定義不能在頂層包含 WITHDISTINCTGROUP BYHAVINGLIMITOFFSET 子句。

  • 檢視定義不能在頂層包含集合運算 (UNIONINTERSECTEXCEPT)。

  • 檢視的 select 列表不能包含任何聚合、視窗函數或集合傳回函數。

自動可更新的檢視可以包含可更新和不可更新的欄位的組合。如果欄位是對底層基礎關聯的可更新欄位的簡單引用,則該欄位是可更新的;否則,該欄位是唯讀的,如果 INSERTUPDATEMERGE 語句嘗試為其賦值,則會引發錯誤。

如果檢視是自動可更新的,系統會將檢視上的任何 INSERTUPDATEDELETEMERGE 語句轉換為底層基礎關聯上的相應語句。完全支援具有 ON CONFLICT UPDATE 子句的 INSERT 語句。

如果一個自動更新的視窗包含 WHERE 條件,這個條件會限制基礎關係中哪些列可以被視窗上的 UPDATEDELETEMERGE 語句修改。然而,UPDATEMERGE 允許更改一列,使得它不再符合 WHERE 條件,因此不再透過視窗可見。同樣地,INSERTMERGE 命令可能會插入不符合 WHERE 條件的基礎關係列,因此這些列也不會透過視窗可見(ON CONFLICT UPDATE 也可能會以類似方式影響透過視窗不可見的現有列)。可以使用 CHECK OPTION 來防止 INSERTUPDATEMERGE 命令建立這種透過視窗不可見的列。

如果自動更新的視窗標記了 security_barrier 屬性,那麼視窗的所有 WHERE 條件(以及任何使用標記為 LEAKPROOF 的運算子的條件)總是在視窗使用者新增的任何條件之前進行評估。詳情請參閱 第 39.5 節。請注意,由於這個原因,最終沒有返回的列(因為它們沒有通過使用者的 WHERE 條件)可能仍然會被鎖定。EXPLAIN 可用於查看哪些條件應用於關係層級(因此不會鎖定列),哪些條件沒有。

更複雜且不滿足所有這些條件的視窗預設為唯讀:系統不允許在視窗上執行 INSERTUPDATEDELETEMERGE。您可以透過在視窗上建立 INSTEAD OF 觸發器來獲得可更新視窗的效果,這些觸發器必須將嘗試在視窗上進行的插入等操作轉換為對其他表格的適當操作。 更多資訊請參閱 CREATE TRIGGER。 另一種可能性是建立規則(請參閱 CREATE RULE),但在實務上,觸發器更容易理解和正確使用。 另請注意,MERGE 不支援具有規則的關聯。

請注意,在視窗上執行插入、更新或刪除的使用者必須具有該視窗上相應的插入、更新或刪除權限。 此外,預設情況下,視窗的所有者必須具有底層基礎關係的相關權限,而執行更新的使用者不需要底層基礎關係上的任何權限(請參閱 第 39.5 節)。但是,如果視窗的 security_invoker 設定為 true,則執行更新的使用者(而不是視窗所有者)必須具有底層基礎關係上的相關權限。

範例

建立一個包含所有喜劇電影的視窗

CREATE VIEW comedies AS
    SELECT *
    FROM films
    WHERE kind = 'Comedy';

這將建立一個視窗,其中包含建立視窗時 film 表格中的欄位。 雖然使用 * 建立視窗,但稍後新增到表格的欄位不會成為視窗的一部分。

建立一個具有 LOCAL CHECK OPTION 的視窗

CREATE VIEW universal_comedies AS
    SELECT *
    FROM comedies
    WHERE classification = 'U'
    WITH LOCAL CHECK OPTION;

這將建立一個基於 comedies 視窗的視窗,僅顯示 kind = 'Comedy'classification = 'U' 的電影。 如果新列沒有 classification = 'U',則任何嘗試在視窗中 INSERTUPDATE 列的動作都將被拒絕,但不會檢查電影 kind

建立一個具有 CASCADED CHECK OPTION 的視窗

CREATE VIEW pg_comedies AS
    SELECT *
    FROM comedies
    WHERE classification = 'PG'
    WITH CASCADED CHECK OPTION;

這將建立一個視窗,該視窗檢查新列的 kindclassification

建立一個混合了可更新和不可更新欄位的視窗

CREATE VIEW comedies AS
    SELECT f.*,
           country_code_to_name(f.country_code) AS country,
           (SELECT avg(r.rating)
            FROM user_ratings r
            WHERE r.film_id = f.id) AS avg_rating
    FROM films f
    WHERE f.kind = 'Comedy';

這個視窗將支援 INSERTUPDATEDELETEfilms 表格中的所有欄位都將是可更新的,而計算欄位 countryavg_rating 將是唯讀的。

建立一個包含從 1 到 100 的數字的遞迴視窗

CREATE RECURSIVE VIEW public.nums_1_100 (n) AS
    VALUES (1)
UNION ALL
    SELECT n+1 FROM nums_1_100 WHERE n < 100;

請注意,雖然遞迴視窗的名稱在此 CREATE 中是使用模式限定名稱,但其內部的自我引用不是模式限定名稱。 這是因為隱式建立的 CTE 的名稱無法使用模式限定名稱。

相容性

CREATE OR REPLACE VIEW 是一個 PostgreSQL 語言擴充。臨時視窗的概念也是如此。 WITH ( ... ) 子句也是一個擴充,安全屏障視窗和安全呼叫者視窗也是如此。

提交更正

如果您發現文件中任何不正確、與您對特定功能的體驗不符或需要進一步澄清的地方,請使用此表單回報文件問題。