程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> DB2數據庫 >> DB2教程 >> DB2 9.5 SQL Procedure Developer 認證考試 735 准備,第3部分

DB2 9.5 SQL Procedure Developer 認證考試 735 准備,第3部分

編輯:DB2教程

開始之前

關於本系列

這六個DB2 SQL Procedure Developer教程討論 SQL Procedural Language的所有基本構造和方法,講解如何在存儲過程、UDF和觸發器中使用SQL Procedural Language,包括錯誤處理和部署。還討論一些 DB2 9.5 高級特性,比如樂觀鎖、層次化查詢和聲明的全局臨時表。本系列討論如何調用存儲過程、UDF和觸發器,以及如何在過程和函數之間共享數據。它介紹 DB2開發工具,包括IBM Data Studio。這些教程為您准備考試的每個部分提供堅實的基礎。但是,您不應該僅僅依靠這些教程准備考試。

關於本教程

本教程深入講解 UDF,重點討論 SQL函數。這是共分六部分的系列中的第三個教程,本系列幫助您准備 IBM DB2 9.5 SQL Procedure Developer 認證考試(考試 735)。

目標

在完成本教程之後,您應該能夠:

掌握函數的正確使用方法

使用CREATE FUNCTION語句創建SQL函數

掌握 SQL函數體的正確結構

從SQL函數返回值和表

調用函數

前提條件

要想參加 DB2 9.5 SQL Procedure Developer 考試,您必須先通過 DB2 9 基礎(730 考試)。可以使用"DB2 9 基礎"教程系列准備此考試。

本教程是為初級和中級 DB2 程序員撰寫的。您應該基本了解關系數據庫的工作方式以及數據庫和數據庫編程構造。此外,還應該熟悉 DB2 Command Line Processor (CLP)的使用方法,了解 SQL的基本知識。

系統需求

要想運行本教程中的示例,需要訪問 DB2 9.5數據庫服務器和DB2提供的SAMPLE數據庫。(可以通過 DB2 Command Line Processor 執行命令 db2sampl 來創建SAMPLE數據庫)。

什麼是函數?

在DB2 中,函數是一組封裝的指令,用來執行一個特定的操作;可以使用一個或多個輸入參數來定制操作,可以使用一個或多個輸出參數來返回結果。有四種函數類型:

標量函數

聚合函數

表函數

行函數

DB2提供許多健壯的內置函數,這些函數在SYSIBM 模式中定義。可用的內置函數包括標量函數(比如UCASE())、聚合函數(比如AVG())、操作符函數(比如“+”)和轉換函數(比如DECIMAL())。通常在查詢的選擇列表和FROM子句中調用函數。

標量函數

標量函數是返回一個標量值的函數。可以使用標量函數執行簡單任務,也可以在標量函數中使用通過函數輸入參數提供的值進行復雜的數學計算。標量函數的示例包括內置函數LENGTH()和SUBSTR()。

在SQL語句中支持表達式的任何地方都可以引用標量函數。當在查詢謂詞中使用時,標量函數可以改進總體性能,因為函數的邏輯作為引用它的SQL語句的組成部分在服務器上直接執行。另外,當在服務器上對一組候選行應用標量函數時,它可以起到過濾器的作用,限制必須返回給客戶機的行數。但是,標量函數也有其局限性。例如,根據設計,標量函數只能返回一個值,無法返回多個值和結果集。另外,在標量函數中不支持事務管理。因此,在標量函數體中無法執行提交和回滾操作。

標量函數通常用來執行基本的數學計算和操作字符串。

聚合函數

聚合函數(也稱為列函數)也返回一個標量值,這個值是一組輸入值的計算結果。通常情況下,這組輸入值來自表中的一列,或來自VALUES子句中的元組。聚合函數的示例包括內置函數MAX()和MIN()。

表函數

表函數向引用它的SQL語句返回一個表。只能在SELECT語句的FROM子句中引用表函數。但是,在能夠應用於只讀視圖的任何操作(例如,聯結、分組操作以及 UNION和INTERSECT 等集操作)中,都可以使用表函數返回的表。

表函數可以發出操作系統調用、從文件中讀取數據以及通過網絡訪問數據。另外,SQL表函數還可以用來封裝修改表數據的SQL語句。(外部表函數不能封裝SQL語句)。但是,與標量函數一樣,在表函數中不支持事務管理。因此,在表函數體中無法執行提交和回滾操作。

表函數通常用來封裝復雜但常用的子查詢,以及為非關系數據提供表格式接口。例如,用戶定義的外部表函數可以讀取電子表格並生成一個數據表,然後可以把生成的數據表直接插入基表或者通過查詢訪問它。

行函數

行函數返回單一表行。行函數只能供用戶定義的結構化類型使用;不能單獨使用行函數,也不能在抽象數據類型的上下文之外的SQL語句中使用。

通常,行函數用於把結構化類型屬性映射到由內置數據類型值組成的行,以便能夠在查詢或SQL操作中訪問結構化類型屬性。例如,假設數據庫有一個用戶定義的結構化數據類型'Manager',此類型擴展另一個結構化數據類型'Employee',其中包含 'Employee'和'Manager' 特有的屬性。如果希望在查詢中引用屬性值,那麼可以創建一個行函數,它把屬性值轉換為查詢可以引用的數據行。

用戶定義的函數

UDF 是用來擴展和增強 DB2 內置函數提供的功能的特殊對象。顧名思義,UDF 是由具有適當權力和/或特權的數據庫用戶創建的。與DB2 內置函數不同,UDF 可以使用系統調用和DB2的管理API,因此能夠在系統、應用程序和數據庫之間進行更多的協作。可以創建五種 UDF:

有源(或模板)

SQL 標量、表或行

外部標量

外部表

OLE DB外部表

通過執行CREATE FUNCTION SQL語句創建(或重新創建)UDF。這個語句有幾種形式,應該使用的形式由要創建的函數的類型決定。

有源(或模板)函數

有源函數是從一個已經向數據庫注冊的函數(稱為源函數)構造出的UDF。有源函數在本質上可以是標量、列或表函數,還可以用它們覆蓋 +、-、*和/ 等操作符。在調用有源函數時,傳遞給它的所有參數被轉換為底層源函數所需的數據類型,然後執行源函數本身。執行完成時,源函數對產生的結果執行必要的轉換,並把控制返回給調用UDF的SQL語句。有源函數最常見的用途是,讓用戶定義的不同數據類型有選擇地繼承內置數據類型的某些語義。

通常,如果以現有函數作為源的UDF的目的是向用戶定義數據類型提供該函數的支持,那麼UDF和有源函數使用相同的名稱。這使用戶能夠用一個用戶定義的不同類型調用相同的函數,而不需要額外的函數定義。一般情況下,多個函數可以使用相同的函數名,只要每個函數的簽名都有些差異即可。

用來創建有源函數的CREATE FUNCTION語句形式的基本語法如下:

清單 1. 用來創建有源函數的CREATE FUNCTION語句

CREATE FUNCTION [FunctionName] ( <<[ParameterName]> [InputDataType] ,...> )
  RETURNS [OutputDataType]
  <SPECIFIC [SpecificName]>
  SOURCE [SourceFunction] <([DataType] ,...)>
  <AS TEMPLATE>

其中:

FunctionName指定要創建的有源函數的名稱。

ParameterName指定一個或多個函數參數的名稱。

InputDataType指定ParameterName 所識別的參數所需的數據類型。

OutputDataType指定函數返回的數據的類型。

SpecificName指定分配給這個UDF的特定名稱。這個名稱可以用來引用或刪除函數;但是,不能用來調用函數。

SourceFunction指定用來創建這個有源函數的現有函數。

DataType指定現有函數的每個參數期望接收的數據類型。

在使用這種形式的CREATE FUNCTION語句時,如果指定了 SPECIFIC子句,就會給創建的UDF 分配一個惟一的名稱。創建函數之後,可以通過在特殊形式的DROP SQL語句 (DROP SPECIFIC FUNCTION [SpecificName]) 中引用這個特定名稱來刪除函數。但是,如果不給 UDF 分配特定名稱,那麼必須在DROP FUNCTION語句中提供函數名和函數的簽名(即放在圓括號中的所有函數參數的數據類型列表)。

如果指定AS TEMPLATE子句,那麼會生成一個函數模板。函數模板是一個不完整的函數,它定義了要返回的數據類型,但是不包含可執行代碼。在聯邦系統中,函數模板被映射到一個數據源(例如Oracle或SQL Server)函數,這樣就可以從聯邦數據庫調用數據源函數。只能在指定為聯邦服務器的數據庫服務器上注冊函數模板。

因此,如果基於內置數據類型INTEGER 創建了一個名為YEAR的數據類型,希望創建一個有源函數AVG(),它應該接收並返回 YEAR值,而且它基於內置函數AVG()(此函數接收並返回 INTEGER值),那麼可以執行下面的CREATE FUNCTION語句:

CREATE FUNCTION AVG(YEAR) RETURNS YEAR
  SOURCE SYSIBM.AVG(INTEGER)

SQL函數

SQL函數是只使用過程式 SQL語句構造的UDF。SQL函數可以是標量函數,也可以返回一行或整個表。

用來創建SQL函數的CREATE FUNCTION語句形式的基本語法如下:

清單 2. 用來創建SQL函數的CREATE FUNCTION語句

CREATE FUNCTION [FunctionName] ( <<[ParameterName]> [InputDataType] ,...> )
  RETURNS [[OutputDataType] |
    TABLE ( [ColumnName] [ColumnDataType] ,... ) |
    ROW ( [ColumnName] [ColumnDataType] ,... )]
  <SPECIFIC [SpecificName]>
  <LANGUAGE SQL>
  <DETERMINISTIC | NOT DETERMINISTIC>
  <EXTERNAL ACTION | NO EXTERNAL ACTION>
  <CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA>
  <STATIC DISPATCH>
  <CALLED ON NULL INPUT>
  [SQLStatements] | RETURN [ReturnStatement]

其中:

FunctionName指定要創建的SQL函數的名稱。

ParameterName指定一個或多個函數參數的名稱。

InputDataType指定ParameterName 所識別的參數所需的數據類型。

OutputDataType指定函數返回的數據的類型。

ColumnName指定函數返回的一列或多列的名稱(如果此函數返回表或行的話)。

ColumnDataType指定ColumnName 所識別的列返回的數據類型。

SpecificName指定分配給這個UDF的特定名稱。這個名稱可以用來引用或刪除函數;但是,不能用來調用函數。

SQLStatements指定在調用函數時執行的一個或多個SQL語句。這些語句組合成一個動態復合SQL語句。

ReturnStatement指定用於返回調用函數的應用程序的RETURN SQL語句。(如果 SQL函數體由動態復合語句組成,那麼它必須包含至少一個RETURN語句;在調用函數時,必須執行一個RETURN語句。如果函數是表函數或行函數,那麼只能包含一個RETURN語句,而且此語句必須是使用的最後一個語句)。

可以看到,這種形式的CREATE FUNCTION語句包含幾個在前一種形式中沒有出現的子句。在許多情況下,這些子句傳達的信息不太直觀,所以我們先詳細討論這些子句,然後再看一個示例。

<LANGUAGE SQL>指定函數是用SQL 編寫的。

<DETERMINISTIC | NOT DETERMINISTIC>表示在用相同的參數值調用函數時,函數是否總是返回相同的標量值、表或行(DETERMINISTIC 代表確定性函數,NOT DETERMINISTIC表示非確定性函數)。如果沒有指定這兩個子句,那麼在用相同的參數值調用函數時函數可能返回不同的結果。

<EXTERNAL ACTION | NO EXTERNAL ACTION>表示函數執行的操作是否會改變不由 DB2 管理的對象的狀態(EXTERNAL ACTION表示會改變,NO EXTERNAL ACTION表示不改變)。外部操作包括發送電子郵件或在外部文件中寫記錄等。如果沒有指定這兩個子句,那麼意味著函數可能執行某種外部操作。

<CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA>表示在UDF 體中編寫的SQL語句的類型。有三個值可用:

CONTAINS SQL:UDF 體包含的可執行SQL語句既不讀數據,也不修改數據。

READS SQL DATA:UDF 體包含的可執行SQL語句讀數據,但是不修改數據。

MODIFIES SQL DATA:UDF 體包含的可執行SQL語句既可以讀數據,也可以修改數據。

<STATIC DISPATCH>表示在函數解析時 DB2 根據函數參數的靜態類型(聲明的類型)選擇函數。

<CALLED ON NULL INPUT>表示無論任何參數是否包含 null值,都調用此函數。

因此,如果希望創建一個名為JULIAN_DATE()的標量 SQL函數,用於將 DB2 日期轉換為儒略日期(自公元前 4713 年 1 月 1 日以來的天數),那麼可以執行下面的CREATE FUNCTION語句:

清單 3. 標量 SQL函數

CREATE FUNCTION julian_date(in_date DATE)
  RETURNS CHAR(7)
  LANGUAGE SQL
  RETURN RTRIM(CHAR(YEAR(in_date))) ||
   SUBSTR(DIGITS(DAYOFYEAR(in_date)), 8)    

外部標量函數

外部標量函數是用C、C++或Java™ 等高級編程語言編寫的返回單一值的函數。創建和實現有源函數或SQL函數的過程非常簡單,但創建和使用外部標量函數(或任何外部函數)的過程就復雜多了。要想創建任何外部函數,必須執行以下步驟:

使用支持的高級編程語言編寫 UDF 體。

編譯 UDF。

鏈接 UDF 以創建庫(或動態鏈接庫)。

調試 UDF 並重復第 2 到第 4 步,直到解決所有問題。

把包含 UDF的庫存儲在服務器工作站上。另外,必須修改包含 UDF的庫文件的系統權限,讓所有用戶都可以執行它。例如,在UNIX 環境中,使用chmod 命令讓一個文件可由所有用戶執行;在Windows 環境中,使用attrib 完成此任務。

使用適當形式的CREATE FUNCTION SQL語句向 DB2數據庫注冊UDF。

完成這些步驟之後,就可以按照使用任何標量函數或表函數的方式使用生成的UDF。

一定要注意一點:因為外部標量函數是用高級編程語言編寫的,而不是SQL,所以提供給函數參數的每個值必須由 SQL數據類型轉換為適當的高級編程語言數據類型,然後才能使用。(如果函數的參數之一需要用戶定義的數據類型,那麼應該先把參數值轉換為適當的內置數據類型,然後再傳遞給外部函數)。同樣,函數返回的任何值必須由高級編程語言數據類型轉換為適當的SQL數據類型,然後才能返回它。另外,如果在外部函數中動態地分配了內存,那麼應該在函數返回之前釋放內存。

用來注冊(已經按以上說明創建的)外部標量函數的CREATE FUNCTION語句形式的基本語法如下:

清單 4. 用來注冊外部標量函數的CREATE FUNCTION語句

CREATE FUNCTION [FunctionName] ( <<[ParameterName]> [InputDataType] ,...> )
  RETURNS [OutputDataType]
  <SPECIFIC [SpecificName]>
  EXTERNAL <NAME [ExternalName] | [IdentifIEr]>
  LANGUAGE [C | Java | CLR | OLE]
  PARAMETER STYLE [DB2GENERAL | Java | SQL]
  <DETERMINISTIC | NOT DETERMINISTIC>
  <FENCED | NOT FENCED>
  <RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT>
  <NO SQL | CONTAINS SQL | READS SQL DATA>
  <STATIC DISPATCH>
  <EXTERNAL ACTION | NO EXTERNAL ACTION>
  <SCRATCHPAD <[100 | [SPSize]]> | NO SCRATCHPAD>
  <DBINFO | NO DBINFO>

其中:

FunctionName指定要創建的外部標量函數的名稱。

ParameterName指定一個或多個函數參數的名稱。

InputDataType指定ParameterName 所識別的參數所需的數據類型。

OutputDataType指定函數返回的數據的類型。

SpecificName指定分配給這個UDF的特定名稱。這個名稱可以用來引用或刪除函數;但是,不能用來調用函數。

ExternalName指定包含要注冊的外部函數的可執行代碼的庫和函數。(稍後詳細討論這個名稱的構造方式)。

IdentifIEr指定包含要注冊的外部函數的可執行代碼的庫,但是這只適用於用C或C++ 編寫的函數。DB2 Database Manager會尋找與庫同名的函數。

SPSize指定用作暫存(scratchpad)區域的內存量(以字節為單位)。

可以看到,這種形式的CREATE FUNCTION語句包含幾個前面沒有出現過的子句。同樣,在許多情況下,這些子句傳達的信息不太直觀,所以我們先詳細討論這些新子句,然後再看一個示例。

EXTERNAL <NAME [ExternalName] | [IdentifIEr]>子句指定兩個信息:包含要注冊的UDF的可執行代碼的庫,以及庫中的函數。用來編寫外部 UDF 體的高級編程語言決定如何提供這兩個名稱。例如,如果外部 UDF 是用C或C++ 編程語言開發的,那麼可以以四種方式指定包含函數體的庫和函數:

'LibraryName'

'LibraryName ! FunctionName'

'AbsolutePath'

'AbsolutePath ! FunctionName'

如果提供庫名而不是絕對路徑,那麼DB2會在/sqllib/function和/sqllib/function/unfenced子目錄中尋找指定的庫名。(在Windows操作系統上,DB2會在LIBPATH或PATH 環境變量指定的目錄路徑中尋找函數)。另一方面,如果提供了絕對路徑,DB2 就在指定的位置尋找庫。(如果既沒有提供庫名,也沒有提供絕對路徑,DB2 就會在默認子目錄中尋找與要注冊的UDF 同名的庫和函數)。如果提供了函數名,DB2 就會在指定的庫中尋找指定的函數名;如果沒有提供函數名,DB2 就會尋找與指定的庫同名的函數。

LANGUAGE [C | Java | CLR | OLE]子句用來指定UDF 體遵守的高級編程語言約定。有四個值可用:

C:DB2 按照處理C函數的方式調用UDF。(這個UDF必須遵守由標准 ANSI C 定義的C語言調用和鏈接約定)。

JAVA:DB2 按照處理Java 類中的方法的方式調用UDF。

CLR:DB2 按照處理.Net 類中的方法的方式調用UDF。(目前,只對在Windows操作系統上運行的UDF 支持 LANGUAGE CLR)。

OLE:DB2 按照處理OLE 自動化對象公開的方法的方式調用UDF。(這個UDF必須遵守 OLE Automation Programmer's Reference 中描述的OLE 自動化數據類型和調用機制)。

PARAMETER STYLE [DB2GENERAL | Java | SQL]子句指定執行調用的應用程序在向 UDF 傳遞值時應該采用的參數傳遞方式。有三種參數傳遞方式:

DB2GENERAL:按照調用Java 方法的調用約定傳遞和返回值。(只能對用Java 編寫的外部 UDF使用此方式)。

JAVA:按照符合Java語言和SQL 規范的調用約定傳遞和返回值。(只能對用Java 編寫的外部 UDF使用此方式)。

SQL:按照符合C語言調用和鏈接約定、OLE 自動化對象公開的方法或.NET 對象的公共靜態方法的調用約定傳遞和返回值。(只能對用C/C++、OLE或.Net 編寫的外部 UDF使用此方式)。

<FENCED | NOT FENCED>子句指定外部 UDF 是否足夠 “可靠”,可以在DB2 Database Manager操作環境的進程/內存空間中運行(NOT FENCED表示可以,FENCED表示不可以)。如果指定FENCED子句(或這兩個子句都未指定),那麼DB2 Database Manager 就不允許函數訪問它的內部資源。

<NO SQL | CONTAINS SQL | READS SQL DATA>子句指定在外部 UDF 體中編寫的SQL語句的類型。有三個值可用:

NO SQL:外部 UDF 體不包含任何 SQL,或者包含不可執行的SQL語句。(不可執行的SQL語句包括INCLUDE和WHENEVER語句等)。

CONTAINS SQL:UDF 體包含的可執行SQL語句既不讀數據,也不修改數據。

READS SQL DATA:UDF 體包含的可執行SQL語句讀數據,但是不修改數據。

<SCRATCHPAD <[100 | [SPSize]]> | NO SCRATCHPAD>子句指定是否為UDF 分配作為持久存儲區域的內存(SCRATCHPAD表示分配,NO SCRATCHPAD表示不分配)。如果指定了 SCRATCHPAD子句,DB2 就會在首次調用此函數時分配適當數量的內存。在創建和填充暫存區域之後,會在各次函數調用之間保留它的內容 —— UDF 在一次調用中對暫存區域所做的任何修改都會保留到下一次調用。

<DBINFO | NO DBINFO>子句表示在調用函數時是否把 DB2 掌握的信息作為額外參數傳遞給 UDF(DBINFO表示傳遞,NO DBINFO表示不傳遞)。如果指定了 DBINFO子句,那麼DB2會傳遞一個數據結構,其中包含的信息包括當前連接的數據庫的名稱、應用程序運行時授權 ID、調用此函數的數據庫服務器的版本、發布版本和修訂級別以及服務器使用的操作系統。

因此,如果希望注冊一個名為CENTER()的外部標量函數,它接受兩個值(一個INTEGER值和一個DOUBLE值)並返回一個DOUBLE值,它存儲在/home/db2inst1/myfuncs 目錄中的“double” 庫中,那麼可以執行下面的CREATE FUNCTION語句:

清單 5.外部標量函數

CREATE FUNCTION center(INT, DOUBLE)
  RETURNS DOUBLE
  EXTERNAL NAME '/home/db2inst1/myfuncs/double'
  LANGUAGE C
  PARAMETER STYLE SQL
  DETERMINISTIC
  NO SQL

外部表函數

與外部標量函數一樣,外部表函數是用高級編程語言編寫的。外部標量函數返回一個標量值,而外部表函數在每次調用時返回一個數據集。外部表函數的強大之處在於,它們能夠讓幾乎任何數據源看起來像是DB2 基表。另外,在聯結操作、分組操作、集操作(例如UNION)和能夠應用於只讀視圖的任何其他操作中,都可以使用外部表函數返回的數據集。

用來注冊外部表函數的CREATE FUNCTION語句形式的基本語法如下:

清單 6. 用來注冊外部表函數的CREATE FUNCTION語句

CREATE FUNCTION [FunctionName] ( <<[ParameterName]> [InputDataType] ,...> )
  RETURNS TABLE ( [ColumnName] [ColumnDataType] ,... )
  <SPECIFIC [SpecificName]>
  EXTERNAL <NAME [ExternalName] | [IdentifIEr]>
  LANGUAGE [C | Java | CLR | OLE]
  PARAMETER STYLE [DB2GENERAL | SQL]
  <DETERMINISTIC | NOT DETERMINISTIC>
  <FENCED | NOT FENCED>
  <RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT>
  <NO SQL | CONTAINS SQL | READS SQL DATA>
  <STATIC DISPATCH>
  <EXTERNAL ACTION | NO EXTERNAL ACTION>
  <SCRATCHPAD <[100 | [SPSize]]> | NO SCRATCHPAD>
  <DBINFO | NO DBINFO>

其中:

FunctionName指定要創建的外部表函數的名稱。

ParameterName指定一個或多個函數參數的名稱。

InputDataType指定ParameterName 所識別的參數所需的數據類型。

ColumnName指定函數返回的一列或多列的名稱。

ColumnDataType指定ColumnName 所識??的列返回的數據類型。

SpecificName指定分配給這個UDF的特定名稱。這個名稱可以用來引用或刪除函數;但是,不能用來調用函數。

ExternalName指定包含要注冊的外部函數的可執行代碼的庫和函數。

IdentifIEr指定包含要注冊的外部函數的可執行代碼的庫,但是這只適用於用C或C++ 編寫的函數。DB2 Database Manager會尋找與庫同名的函數。

SPSize指定用作scratchpad 區域的內存量(以字節為單位)。

因此,如果希望注冊一個名為EMPDATA()的外部表函數,它接受兩個長度可變的字符串值,返回一個包含職員信息的數據集(信息取自一個ASCII 文件),它存儲在/home/db2inst1/myfuncs 目錄中的“EMPDATA” 庫中,那麼可以執行下面的CREATE FUNCTION語句:

清單 7.外部表函數

CREATE FUNCTION empdata (VARCHAR(30), VARCHAR(255))
  RETURNS TABLE (empid INT, lname CHAR(20), fname CHAR(20))
  EXTERNAL NAME '/home/db2inst1/myfuncs/EMPDATA'
  LANGUAGE C
  PARAMETER STYLE SQL
  DETERMINISTIC
  NOT FENCED
  NO SQL
  NO EXTERNAL ACTION

OLE DB外部表函數

Microsoft OLE DB 是一組應用程序編程接口 (API),用於訪問各種數據源。數據源由數據本身、相關聯的數據庫管理系統 (DBMS)、運行DBMS的平台以及用來訪問此平台的網絡組成。OLE DB 可以為OLE Component Object Model (COM) 環境中的所有數據源類型提供訪問。

除了 CLI/ODBC提供的功能之外,OLE DB 定義的接口還可以訪問無法通過 SQL 訪問的數據。OLE DB 通過定義一組標准接口來促進應用程序集成,這些接口包含與語義相關的函數,應用程序可以通過這些函數訪問其他應用程序的服務。接口是用於組件-對象交互的二進制標准,每個接口包含一組函數,它們為實現接口的對象(提供者)和使用接口的客戶機(消費者)之間的交互定義一個“合同”。有兩類 OLE DB提供者:OLE DB數據提供者,它們本身擁有數據並以行集的形式公開表格式的數據;OLE DB 服務提供者,它們本身不擁有數據,而是通過 OLE DB 接口產生和消費數據來封裝某些服務。

與外部表函數一樣,外部 OLE DB表函數是用高級編程語言編寫的。但是,對於 OLE DB表函數,可以使用一個通用的內置 OLE DB 消費者訪問任何 OLE DB提供者來訪問數據;只需注冊一個OLE DB表函數並作為數據源引用適當的OLE DB提供者。不需要編寫額外的代碼。與外部表函數一樣,在聯結操作、分組操作、集操作(例如UNION)和能夠應用於只讀視圖的任何其他操作中,都可以使用外部 OLE DB表函數返回的表。例如,可以定義一個OLE DB表函數,它返回來自Microsoft Access數據庫或Microsoft Exchange地址簿的表;然後創建一個報告,報告無縫地組合來自這個OLE DB表和DB2數據庫的數據。

一定要注意一點:要想對DB2數據庫使用OLE DB表函數,必須安裝OLE DB 2.0或更高版本,這可以從Microsoft 獲得。關於系統需求和特定數據源可用的OLE DB提供者的更多信息,請查閱數據源的文檔。

用來注冊OLE DB外部表函數的CREATE FUNCTION語句形式的基本語法見清單 8。

清單 8. 用來注冊OLE DB外部表函數的CREATE FUNCTION語句

CREATE FUNCTION [FunctionName] ( <<[ParameterName]> [InputDataType] ,...> )
  RETURNS TABLE ( [ColumnName] [ColumnDataType] ,... )
  <SPECIFIC [SpecificName]>
  EXTERNAL <NAME [ExternalName]>
  LANGUAGE OLEDB
  <DETERMINISTIC | NOT DETERMINISTIC>
  <RETURNS NULL ON NULL INPUT | CALLED ON NULL INPUT>
  <EXTERNAL ACTION | NO EXTERNAL ACTION>
  <CARDINALITY [NumRows]>

其中:

FunctionName指定要創建的OLE DB外部表函數的名稱。

ParameterName指定一個或多個函數參數的名稱。

InputDataType指定ParameterName 所識別的參數所需的數據類型。

ColumnName指定函數返回的一列或多列的名稱。

ColumnDataType指定ColumnName 所識別的列返回的數據類型。

SpecificName指定分配給這個UDF的特定名稱。這個名稱可以用來引用或刪除函數;但是,不能用來調用函數。

ExternalName 為要注冊的函數指定引用的外部表和OLE DB提供者。指定外部表和OLE DB提供者的語法如下:

'[Server]!<Rowset>'

'!<Rowset>![ConnectString] <!COLLATING_SEQUENCE = [N | Y]>'

其中:

Server指定由 CREATE SERVER SQL語句定義的數據源的本地名稱。

Rowset指定OLE DB提供者公開的行集(表)。

ConnectString指定一個連接字符串,其中包含通過 OLE DB提供者連接數據源所需的初始化屬性。此字符串由一系列關鍵字=值 對組成,與CLI/ODBC函數SQLDriverConnect()使用的連接字符串相似。

注意:<!COLLATING_SEQUENCE = [N | Y]>子句指定是否使用與DB2相同的比較次序訪問數據源。

NumRows指定函數返回的行數的估計值。(此值只用於優化)。

因此,如果希望注冊一個名為ORDERS()的OLE DB外部表函數,從一個Microsoft Access數據庫獲取訂單信息,那麼可以執行清單 9 所示的CREATE FUNCTION語句:

清單 9. OLE DB外部表函數

CREATE FUNCTION orders()
  RETURNS TABLE (orderid   INTEGER,
          customerid  CHAR(5),
          employeeid  INTEGER,
          orderdate  TIMESTAMP,
          requiredate TIMESTAMP,
          shipdate   TIMESTAMP,
          shipcharges DECIMAL(19,4))
  LANGUAGE OLEDB
  EXTERNAL NAME '!orders!Provider=Microsoft.Jet.OLEDB.3.51;
    Data Source=c:sqllibsamplesoledbnwind.mdb'

SQL函數的結構

在前面,您已經看到 SQL函數由以下部分組成:

函數名

一系列參數聲明(如果有參數的話)

函數返回值的聲明

一個或多個函數選項

函數體

圖 1 給出用來定義每個部分的CREATE FUNCTION語句元素。

圖 1. SQL函數的結構

下面通過一些示例解釋這個結構。

單語句 SQL 標量函數

顧名思義,單語句 SQL函數的函數體只包含一個SQL語句。單語句 SQL 標量函數是返回一個標量值的單語句 SQL函數。

圖 2 給出的單語句 SQL 標量函數用來顯示當前的月份名稱。

圖 2. 單語句 SQL 標量函數

單語句 SQL表函數

單語句 SQL表函數的函數體由一個SQL語句組成,它向引用它的SQL語句返回一個表。單語句 SQL表函數與單語句 SQL 標量函數的差異是RETURNS子句的編寫方式不同;並不聲明要返回一個標量數據類型的值,而是定義作為函數結果的臨時表的列。圖 4 給出一個單語句 SQL表函數,它返回的結果集包含男性職員的工資信息。

圖 4. 單語句 SQL表函數

復合語句 SQL 標量函數

復合SQL語句是一種可以把多個SQL語句組合成一個可執行塊的特殊機制。盡管復合語句中使用的每個SQL語句都可以單獨執行,但是把它們組合在一起會減少處理它們所需的開銷;DB2 把復合語句編譯為單一 SQL語句。復合SQL語句本身適合用來創建簡短的腳本,執行控制流非常簡單但數據流很大的小型邏輯工作單元。在SQL函數體中使用(與支持的SQL PL語句結合使用)時,可以執行更復雜的邏輯。圖 6 給出一個SQL 標量函數,其函數體包含一個復合SQL語句。此函數用於查明本月的最後一天是星期幾。

圖 6. 復合語句 SQL 標量函數

復合語句 SQL表函數

復合語句 SQL表函數的函數體由一個復合SQL語句組成,它向引用它的SQL語句返回一個表。與單語句 SQL表函數一樣,復合語句 SQL表函數與SQL 標量函數的差異是RETURNS子句的編寫方式不同;並不聲明要返回一個標量數據類型的值,而是定義作為函數結果的臨時表的列。圖 8 給出一個復合語句 SQL表函數,它返回的結果集包含工資高於所有職員平均工資的所有職員的工資信息。

圖 8. 復合語句 SQL表函數

與變量相關的語句

DECLARE [Variable] DEFAULT [Value]

DECLARE [Condition]

SET (assignment-statement)

條件語句

IF

循環語句

FOR

WHILE

控制轉移語句

CALL

ITERATE

LEAVE

RETURN

錯誤管理語句

SIGNAL

圖 10 給出的復合語句 SQL 標量函數包含幾個SQL PL語句。

圖 10. 包含 SQL PL語句的SQL 標量函數

SQL函數中的錯誤處理

在理想情況下,SQL函數中的錯誤處理,它捕捉和處理在函數范圍內可能發生的任何錯誤和/或警告,然後把錯誤的相關信息返回給調用函數的用戶或應用程序。最容易的錯誤處理方法是使用SIGNAL SQL語句。此語句的基本語法如下:

SIGNAL [Condition_Value]
SET MESSAGE_TEXT = [Message]

SIGNAL SQLSTATE <VALUE> [SQLSTATE_Value]
SET MESSAGE_TEXT = [Message]

其中:

Condition_Value表示在包含 SIGNAL語句的復合語句中聲明的一個條件。

SQLSTATE_Value指定一個包含五個字符的字符串常量,它代表 SQLSTATE值。

Message指定一個最多 70 個字符的字符串,它描述遇到的錯誤或警告。

例如,圖 11 給出一個復合語句 SQL 標量函數,它把一個DECIMAL值轉換為DATE值,其中包含捕捉和處理錯誤的代碼。在此函數中,為SQLSTATE 22007 定義一個條件 —— 這個SQLSTATE值表示日期無效(由圖 11 中的第一項表示),如果輸入值是0,就使用SIGNAL語句把警告或錯誤告知調用函數的用戶或應用程序(由圖 11 中的第二項表示)。

圖 11. 包含流控制語句的SQL 標量函數

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved