在關系數據庫系統內部,應用程序和實際數據庫之間的主要交互都是以會話或連接的 SQL 語句形式來實現的。過去,為了在相同會話中實現不同 SQL 語句之間的信息共享,發出 SQL 語句的應用程序必須將語句輸出參數集(本地變量)的值復制到另一個語句的輸入本地變量中。此外,數據庫系統本身定義或包含的 SQL 語句,例如用來定義觸發器和視圖的 SQL 語句,根本不能夠訪問這些共享信息。
總之,種種約束限制了關系數據庫系統的靈活性,並因此限制了系統用戶在數據庫內部實現復雜、交互式模型的能力。這類系統的用戶不得不在自己的應用程序或 SQL 過程中添加支持邏輯,以便在關系數據庫系統中訪問和傳遞用戶應用程序信息和內部數據庫信息。用戶還需對其應用程序邏輯進行增強,以確保被傳遞和訪問的信息的安全性。
為克服這種約束並最大化實現關系數據庫系統的靈活性,DB2 V9.5 引入了全局變量的概念。通過引入全局變量,用戶現在可以在關系數據庫內部輕松地構建復雜系統,同時可在同一會話的 SQL 語句之間共享信息,或者使用數據庫系統定義或包含的 SQL 語句訪問信息。實現這些任務無需任何應用程序邏輯,從而支持信息傳遞。本文的目的是介紹這種新特性並解釋如何使用它才能發揮其潛力。
首先,了解什麼是全局變量以及它涉及的基本操作。然後查看一些有趣的場景,了解全局變量的使用。最後,本文將更加深入地闡述一些與全局變量有關的主題。
什麼是全局變量?
全局變量表示一個可以使用 SQL 語句訪問和修改的可變值。在 DB2 中,這些變量被實現為一種新型數據庫對象,其定義保存在數據庫編目中。編目中保存的是全局變量的定義而非實際的值,了解這一點非常重要。這樣做是因為全局變量具有一個會話(連接)范圍。這意味著每個會話都可以使用編目中保存的全局變量,但是每個會話擁有自己的私有值來操作和使用。其他會話都不能訪問這個值。
全局變量的另一重要方面是,當考慮到信息安全問題時,可以控制對信息的訪問。需要有特定的權限才能創建或刪除全局變量,以及讀取或修改其內容。這條規則同樣適用於全局變量的定義 —— 與全局變量相關的權限也在系統編目中進行了定義。
創建和刪除全局變量
要創建一個全局變量,可以使用新的 CREATE VARIABLE SQL 語句。您需要對模式使用 SYSADM, DBADM 權限或 CREATE_IN。例如,要創建一個全局變量來表示默認的打印機,應該發出如下語句:
CREATE VARIABLE mySchema.defaultPrinter VARCHAR(30)
DEFAULT 'Printer001'
mySchema.defaultPrinter 表示變量的名稱。請注意,全局變量的名稱由兩部分組成,即模式的名稱和其中的變量的名稱。如果沒有具體指定模式,則默認為當前模式。
VARCHAR(30) 表示變量的數據類型。數據類型可以是 DB2 內置數據類型、獨特的類型或引用類型。注意,不能為全局變量指定 CLOB、DBCLOB、BLOB、LONG VARCHAR、LONG VARGRAPHIC、XML、ARRAY 或結構化類型。
如果在第一次引用全局變量沒有為全局變量指定其他值,那麼使用 DEFAULT ‘Printer001’ 表示它的默認值。默認指定的子句可以為一個常量、一個特殊的寄存器、另一個全局變量、一個表達式或關鍵字 NULL。表達式可以是 SQL Reference Guide 的 “Expressions” 部分中定義的任何類型的表達式(請參見 參考資料)。如果沒有指定默認值,則初始變量為 NULL。表達式的最大大小為 64K。在第一次引用時,默認表達式將為全局變量計算一個值。只要不修改 SQL 中的數據或不會在 DB2 引擎以外執行任何操作,則可以使用 DB2 允許的任何表達式。此外,表達式在分配時必須與變量數據類型兼容。
下面列出了其他一些全局變量示例:
要創建表示用戶第一次連接時間的變量,使用以下語句:
CREATE VARIABLE loginTime TIMESTAMP DEFAULT CURRENT TIMESTAMP
要創建表示員工所屬部門的變量,使用以下語句:
CREATE VARIABLE schema1.gvDeptno INTEGER DEFAULT
((select deptno from hr.employees where empUser = SESSION_USER));
如果希望創建一個全局變量表示最高級安全級別,使用下面的語句:
CREATE VARIABLE mySchema.SecurityLevel CHAR(5) DEFAULT NULL
請注意,一旦創建完畢,全局變量的 length 屬性和數據類型將不能更改。此外,您不能更改全局變量定義,包括其默認值。
如果您不希望再保存全局變量的定義,則需要刪除它。刪除全局變量和刪除其他數據庫對象需要使用相同的權限(請參考 SQL Reference 中的完整權限列表)。例如,要刪除我們前面創建的表示默認打印機的全局變量,應使用以下語句:
DROP VARIABLE mySchema.defaultPrinter
where:
mySchema.defaultPrinter 是變量的名稱。如果沒有指定模式,則遵守特定規則來確定模式名稱。本文稍後的內容將討論名稱解析。
請注意,如果函數、方法、觸發器或視圖中引用了某個全局變量,則不能刪除該變量。
使用全局變量
創建了全局變量之後,如果擁有相應的權限,數據庫中的任何會話都可以使用它。READ 權限用於引用全局變量,而 WRITE 權限用於修改全局變量的值。GRANT 語句允許授權用戶對這些權限進行授權,而 REVOKE 語句用於刪除這些權限。全局變量的所有者被顯式授予了有關該變量的所有權限。
任何表達式都可以引用全局變量,只要該表達式不需要保持確定性。以下這些情況需要確定性表達式,因此不能使用全局變量:
-檢查約束
-生成的列的定義
-刷新直接 Materialized Query Tables (MQTs)
-如上文所述,每個會話對於給定的全局變量都具有自己的私有值。當在會話中第一次引用時,全局變量將進行實例化來獲得其默認值。
要查詢當前用戶所在部門的全部員工,使用以下語句:
SELECT * FROM hr.employees WHERE> deptno = schema1.gvDeptno
要查詢本地變量 hv_depnot 的用戶部門編號,使用以下語句:
EXEC SQL VALUES schema1.gvDeptno INTO :hv_deptno
要查詢用戶的部門編號,使用以下語句:
VALUES schema1.gvDeptno
可以使用 SET, SELECT INTO, VALUES INTO 語句改變全局變量的值。也可以作為調用語句的 out 或 input 參數的實參進行修改。
例如,要將 mySchema.defaultPrinter 變量的值修改為 “Printer002”,使用以下語句:
SET mySchema.defaultPrinter = 'Printer002'
要修改 schema1.activeEmployees 的值,使用以下語句:
EXEC SQL SELECT count(*) INTO schema1.activeEmployees
FROM hr.employees WHERE active = ‘Y’
示例
現在您已經了解了如何使用全局變量執行簡單的操作,本節將提供一些有趣的場景以展示如何使用它們。
使用全局變量關閉觸發器以進行維護
全局變量的一項有趣應用就是控制觸發器的行為。例如,如果您的表具有以下觸發器:
CREATE TRIGGER validate_t
BEFORE INSERT ON T
REFERENCING NEW AS N FOR EACH ROW
WHEN (N.ORDER_DATE < CURRENT TIMESTAMP – 7 DAYS)
SIGNAL SQLSTATE ‘38000’
SET MESSAGE TEXT = ‘ORDER DATE TOO OLD’;
如果 DBA 希望進行一些維護並向表插入一些較舊的數據,他必須阻止其他用戶向表插入新的數據、刪除觸發器、執行維護、重新創建觸發器,維護完之後才能允許用戶插入數據。