DECLARE — 定義一個遊標
DECLAREname
[ BINARY ] [ ASENSITIVE | INSENSITIVE ] [ [ NO ] SCROLL ] CURSOR [ { WITH | WITHOUT } HOLD ] FORquery
DECLARE
允許使用者建立遊標,遊標可用於一次性從一個大型查詢中檢索少量行。在建立遊標後,可以使用 FETCH
命令從遊標中獲取行。
本文件描述了 SQL 命令級別的遊標用法。如果您嘗試在 PL/pgSQL 函式中使用遊標,規則會有所不同——請參閱 第 41.7 節。
name
要建立的遊標的名稱。此名稱必須與會話中的任何其他活動遊標名稱都不同。
BINARY
導致遊標以二進位制格式而不是文字格式返回資料。
ASENSITIVE
INSENSITIVE
遊標的敏感性決定了在宣告遊標後,同一事務中對遊標底層資料所做的更改是否對遊標可見。INSENSITIVE
表示這些更改不可見,ASENSITIVE
表示行為取決於具體實現。第三種行為 SENSITIVE
(表示此類更改對遊標可見)在 PostgreSQL 中不可用。在 PostgreSQL 中,所有遊標都是不敏感的;因此,這些關鍵字沒有實際作用,只是為了與 SQL 標準相容而接受。
指定 INSENSITIVE
和 FOR UPDATE
或 FOR SHARE
是一個錯誤。
SCROLL
NO SCROLL
SCROLL
指定了遊標可以用於非順序地(例如,向後)檢索行。根據查詢執行計劃的複雜性,指定 SCROLL
可能會對查詢的執行時間造成效能損失。NO SCROLL
指定了遊標不能用於非順序地檢索行。預設情況下允許在某些情況下進行滾動;這不等同於指定 SCROLL
。有關詳細資訊,請參見下面的 註釋。
WITH HOLD
WITHOUT HOLD
WITH HOLD
指定了遊標可以在建立它的事務成功提交後繼續使用。WITHOUT HOLD
指定了遊標不能在建立它的事務之外使用。如果既沒有指定 WITHOUT HOLD
也沒有指定 WITH HOLD
,則預設是 WITHOUT HOLD
。
query
關鍵字 ASENSITIVE
、BINARY
、INSENSITIVE
和 SCROLL
可以按任意順序出現。
普通遊標以文字格式返回資料,與 SELECT
生成的結果相同。BINARY
選項指定了遊標應以二進位制格式返回資料。這減少了伺服器和客戶端的轉換開銷,但需要程式設計師花費更多精力來處理依賴於平臺的二進位制資料格式。例如,如果一個查詢從整數列返回值為 1,使用預設遊標您將得到字串 1
,而使用二進位制遊標您將得到一個 4 位元組欄位,其中包含該值的內部表示(採用大端位元組序)。
應謹慎使用二進位制遊標。許多應用程式,包括 psql,都無法處理二進位制遊標,並且期望資料以文字格式返回。
當客戶端應用程式使用“擴充套件查詢”協議發出 FETCH
命令時,Bind 協議訊息會指定資料是以文字格式還是二進位制格式檢索。此選擇會覆蓋遊標的定義方式。因此,在使用擴充套件查詢協議時,二進位制遊標的概念本身已過時——任何遊標都可以被視為文字或二進位制。
除非指定了 WITH HOLD
,否則此命令建立的遊標只能在當前事務中使用。因此,在事務塊之外使用不帶 WITH HOLD
的 DECLARE
是無用的:遊標僅在語句完成後生存。因此,如果在事務塊外使用此類命令,PostgreSQL 會報告錯誤。請使用 BEGIN
和 COMMIT
(或 ROLLBACK
)來定義事務塊。
如果指定了 WITH HOLD
並且建立遊標的事務成功提交,則該遊標可以被同一會話中的後續事務繼續訪問。(但如果建立事務被中止,則遊標會被刪除。)透過 WITH HOLD
建立的遊標會在對其發出顯式的 CLOSE
命令時關閉,或者在會話結束時關閉。在當前實現中,由保持的遊標表示的行會被複制到臨時檔案或記憶體區域,以便它們可供後續事務使用。
當查詢包含 FOR UPDATE
或 FOR SHARE
時,不能指定 WITH HOLD
。
當定義一個將用於向後提取的遊標時,應指定 SCROLL
選項。這是 SQL 標準的要求。然而,為了與早期版本相容,如果遊標的查詢計劃足夠簡單,不需要額外的開銷來支援它,PostgreSQL 將允許在沒有 SCROLL
的情況下向後提取。但是,建議應用程式開發人員不要依賴於從未使用 SCROLL
建立的遊標進行向後提取。如果指定了 NO SCROLL
,則無論如何都不允許向後提取。
當查詢包含 FOR UPDATE
或 FOR SHARE
時,也禁止向後提取;因此,在這種情況下不能指定 SCROLL
。
當滾動遊標呼叫任何易變函式時(參見 第 36.7 節),可能會產生意外結果。當重新提取先前已提取的行時,函式可能會被重新執行,可能導致結果與第一次不同。最好為涉及易變函式的查詢指定 NO SCROLL
。如果不可行,一種解決方法是宣告遊標為 SCROLL WITH HOLD
並在讀取遊標中的任何行之前提交事務。這將強制遊標的整個輸出物化到臨時儲存中,從而確保易變函式對每一行只執行一次。
如果遊標的查詢包含 FOR UPDATE
或 FOR SHARE
,則在首次提取時會鎖定返回的行,其方式與帶有這些選項的普通 SELECT
命令相同。此外,返回的行將是最新的版本。
通常建議使用 FOR UPDATE
,如果遊標打算與 UPDATE ... WHERE CURRENT OF
或 DELETE ... WHERE CURRENT OF
一起使用。使用 FOR UPDATE
可以防止其他會話在行被提取和更新之間更改這些行。如果沒有 FOR UPDATE
,後續的 WHERE CURRENT OF
命令將在遊標建立後行被更改時無效。
使用 FOR UPDATE
的另一個原因是,如果沒有它,後續的 WHERE CURRENT OF
可能會失敗,如果遊標查詢不滿足 SQL 標準關於“簡單可更新”的規則(特別是,遊標必須只引用一個表,並且不能使用分組或 ORDER BY
)。不可簡單更新的遊標可能會工作,也可能不會,具體取決於計劃選擇的細節;因此,在最壞的情況下,應用程式在測試中可能會正常工作,然後在生產環境中失敗。如果指定了 FOR UPDATE
,則遊標保證是可更新的。
不將 FOR UPDATE
與 WHERE CURRENT OF
一起使用的主要原因是,如果您需要遊標是可滾動的,或者需要與併發更新隔離(即,繼續顯示舊資料)。如果這是要求,請密切注意上面顯示的注意事項。
SQL 標準僅為嵌入式 SQL 中的遊標提供了規定。SQL。 PostgreSQL 伺服器不實現遊標的 OPEN
語句;宣告遊標時,它就被認為是開啟的。但是,ECPG(PostgreSQL 的嵌入式 SQL 預處理器)支援標準的 SQL 遊標約定,包括涉及 DECLARE
和 OPEN
語句的約定。
已開啟遊標的底層伺服器資料結構稱為 portal。Portal 名稱在客戶端協議中公開:如果客戶端知道 portal 的名稱,則可以直接從已開啟的 portal 中獲取行。使用 DECLARE
建立遊標時,portal 名稱與遊標名稱相同。
您可以透過查詢 pg_cursors
系統檢視來檢視所有可用的遊標。
SQL 標準只允許在嵌入式 SQLSQL和模組中使用遊標。 PostgreSQL 允許互動式使用遊標。
根據 SQL 標準,對不敏感遊標的 UPDATE ... WHERE CURRENT OF
和 DELETE ... WHERE CURRENT OF
語句所做的更改在此遊標中是可見的。 PostgreSQL 將這些語句視為所有其他資料更改語句,即它們在不敏感遊標中是不可見的。
二進位制遊標是 PostgreSQL 的擴充套件。
如果您在文件中發現任何不正確、不符合您對特定功能的實際體驗或需要進一步澄清的內容,請使用 此表格 來報告文件問題。