DB2中實現正則表達式



正則表達式用於查找和替換字符串中的模式。正則表達式是用某種語法定義的,正則表達式引擎采用這種語法並將它與字符串進行比較。引擎返回字符串是否與語法匹配的指示;也即,該字符串是否包含能夠從該語法派生的子串。此外,引擎還能夠返回匹配的子串。術語“模式(pattern)”用來表示語法。

  最基本的模式僅由單個字母組成。當與該模式進行比較時,包含這個字母的字符串就是一個“匹配”。例如,如果模式是“a”,則字符串“abcd”就是一個匹配,而字符串“xyz”則不是。正則表達式的強大功能來自於預定義的運算符(也稱為元字符),它們可以用很小的空間來表示模式。根據“方言”和受支持的功能,可以使用不同的元字符。通常,其中的一些可用字符如下:

| — 二中擇一
[ ] — 分組
* — 多次出現(也匹配零次出現)
+ — 多次出現(至少一次)
? — 隨意的出現次數
\\\\ — 反斜杠

  不同的系統實現了常用正則表達式的各種擴展。編程語言 Perl 中使用的正則表達式支持進一步的縮寫。本文中所用的庫實現了這些擴展。下面摘錄了其中部分可以在 Perl 正則表達式語言中使用的縮寫:


\\s — 任意空白字符
\\w — 任意字母數字字符
\\d — 任意數字字符

  另一個更高級的示例是模式“[A-Z]* = ([0-9]|0x00);”。與這個模式相匹配的字符串包含這樣的子串:它由幾個大寫字母、后面跟上一個空格、一個等號、另一個空格,然后是一個數字或字符串“0x00”組成。該子串的最后一個字符必須是分號。使用 Perl,這個模式可以表示為“\\w* = (\\d|0x00);”。“NM = 0x00;”和“X = 7;”是兩個可以與該模式匹配的字符串。但字符串“Z = 123;”不能匹配,因為 123 是由三個數字所組成的。

  DB2 中的字符串匹配

  除了 Extender 以外,DB2 還允許幾種用於文本比較的函數和運算符。但那些函數和運算符要么在用於模式匹配的功能方面有限制,要么就是會給可能使用它們的查詢帶來復雜性。這里簡要地摘錄幾個可用的功能:

= 或 <> 謂詞:逐字符地比較兩個字符串是否相等。
LIKE 謂詞:使用通配符的基本模式匹配。
LOCATE 函數:在字符串中查找子串。

  盡管也可以用 SQL 運算符表示模式“[A-Z]* = ([0-9]|0x00);”,但那樣會很麻煩。例如,下列 SELECT 語句的 WHERE 子句中所使用的謂詞會匹配字符串“str”中等號之后的部分,如 清單 1所示:

清單 1. 使用 LIKE 匹配模式


SELECT str
FROM   strTable
WHERE ( str LIKE '% = 0;%' OR str LIKE '% = 1;%' OR str LIKE '% = 2;%' 
 OR str LIKE '% = 3;%' OR str LIKE '% = 4;%' OR str LIKE '% = 5;%' 
 OR str LIKE '% = 7;%' OR str LIKE '% = 7;%' OR str LIKE '% = 8;%' 
 OR str LIKE '% = 9;%' OR str LIKE '% = 0x00;%' )

  這增加了可以匹配“[A-Z]*”子模式的謂詞的復雜度,這可以使用對整個字符串進行迭代並進行逐字符比較的函數來完成,但您會發現使用內置功能既冗長又復雜。

  示例方案

  讓我們定義下列清單( 清單 2)並插入幾行:

清單 2. 創建我們的樣本表


CREATE TABLE strTable ( c1 INTEGER, str VARCHAR(500) );
INSERT INTO strTable VALUES ( 1, 'some text;' ),
                            ( 2, 'variable = 1234;' ),
                            ( 3, 'var2 = ''string variable'';' ),
                            ( 4, 'xyz = ' ),
                            ( 5, 'myVar = 0x00;' ),
                            ( 6, '# comment' ),
                            ( 7, 'abc = def' );
                            

  這個 清單及其數據被用於下面的所有示例。


SELECT * FROM strTable;

C1          STR
----------- ------------------------------
          1 some text;
          2 variable = 1234;
          3 var2 = 'string variable';
          4 xyz = 
          5 myVar = 0x00;
          6 # comment
          7 abc = def

  7 record(s) selected.

  實現模式匹配函數

  您可以使用 DB2 的可擴展機制,在 SQL 語句內使用 UDF,以便顯著地改善這種情形。通過定義名為 regex1 的 UDF(它采用模式和字符串作為輸入參數), 清單 1中的 WHERE 子句現在可以寫得象 清單 3中所示的那樣:

清單 3. 使用 regex UDF 來簡化模式匹配


SELECT str
FROM   strTable
WHERE regex1('\\w* = (\\d|0x00);', str) = 1

  在本示例中,使用帶有 Perl 擴展的正則表達式來匹配完整的模式,而不僅僅是 清單 1中給出的 LIKE 謂詞所對應的部分模式。正如您所看到的,使用函數來為該模式編寫謂詞比用 LIKE 謂詞表示同樣的語義要容易得多。

  實現 UDF

  在我的示例實現中,我選擇了現有的名為 PCRE(Perl 兼容的正則表達式,Perl-compatible regular expression)的模式匹配引擎。該引擎提供了用來處理模式和執行匹配的 C API。該引擎和查詢中所用的 SQL 語言之間“缺失的部分”是 UDF。該 UDF 由兩部分組成:

  • 數據庫中創建(或注冊)該函數的 CREATE FUNCTION 語句。
  • 該函數的主體,它實現了用於正則表達式匹配引擎的 C API 調用的封裝器

  清單 4顯示了用於創建該函數的 SQL 語句。

清單 4. 注冊 regex1 函數


CREATE FUNCTION regex1(pattern VARCHAR(2048), string CLOB(10M))
    RETURNS INTEGER
    SPECIFIC regexSimple
    EXTERNAL NAME 'regexUdf!regexpSimple'
    LANGUAGE C
    PARAMETER STYLE DB2SQL
    DETERMINISTIC
    NOT FENCED
    RETURNS NULL ON NULL INPUT
    NO SQL
    NO EXTERNAL ACTION
    ALLOW PARALLEL;

  注:請參閱 DB2 SQL Reference以獲取所有子句的詳細含義。可以修改參數的長度以適應您的需求。我在此處展示某些值並沒有任何推薦使用它們的用意。

  第二部分由一小段 C 代碼組成,它實現了 UDF 入口點。在查詢執行期間,DB2 為每個要與模式匹配的行調用這個入口點。 清單 5中的示例列出了該代碼的清單。有關 pcre_* 函數和宏的描述,請參考 PCRE 庫的文檔。有關 C 代碼的編譯和共享庫的構建,請參考 DB2 Application Development Guide

  清單 5. 實現 rege1x UDF 入口點的 C 代碼


#include 
#include 

void regexpSimple(
    // input parameters
    SQLUDF_VARCHAR *pattern,      SQLUDF_CLOB *str,
    // output
    SQLUDF_INTEGER *match,
    // null indicators
    SQLUDF_NULLIND *pattern_ind,  SQLUDF_NULLIND *str_ind,
    SQLUDF_NULLIND *match_ind,
    SQLUDF_TRAIL_ARGS)
{
    pcre *re = NULL;
    const char *error = NULL;
    int errOffset = 0;
    int rc = 0;

    // we assume successful return
    *match_ind = 0;

    // compile the pattern to its internal representation
    re = pcre_compile(pattern, 0 /* default options */, &error,
        &errOffset, NULL);
    if (re == NULL) {
        snprintf(SQLUDF_MSGTX, 70, "Regexp compilation failed at "
            "offset %d: %s\\n", errOffset, error);
        strcpy(SQLUDF_STATE, "38900");
        (*pcre_free)(re);
        return;
    }

    // match the string againts the pattern
    rc = pcre_exec(re, NULL, str->data, str->length, 0,
            0 /* default options */, NULL, 0);
    switch (rc) {
      case PCRE_ERROR_NOMATCH:
        *match = 0;
        break;
      case PCRE_ERROR_BADOPTION:
        snprintf(SQLUDF_MSGTX, 70, "An unrecognized bit was set in the "
            "options argument");
        strcpy(SQLUDF_STATE, "38901");
        break;
      case PCRE_ERROR_NOMEMORY:
        snprintf(SQLUDF_MSGTX, 70, "Not enough memory available.");
        strcpy(SQLUDF_STATE, "38902");
        break;
      default:
        if (rc < 0) {
            snprintf(SQLUDF_MSGTX, 70, "A regexp match error "
                "occured: %d", rc);
            strcpy(SQLUDF_STATE, "38903");
        }
        else {
            *match = 1;
        }
        break;
    }

    // cleanup
    (*pcre_free)(re);
    return;
}

  用法示例

  下列查詢試圖從表 strTable 中找出包含注釋文本的所有字符串。注釋以“#”開頭,所以模式是“#”后跟非空文本。


SELECT c1, str
FROM   strTable
WHERE  regex1('#\\s*\\w+', str) = 1;

  結果只包含 c1 = 6 的行。


C1          STR
----------- -------------------------
          6 # comment;

  1 record(s) selected.

  在第二個示例中,我們試圖找到這種賦值形式的字符串;即“text = text”。為了進一步縮小范圍,我們只查找那些右端為數值的賦值。將十六進制表示法作為有效數值對待。


SELECT c1, str
FROM   strTable
WHERE  regex1('\\w+\\s*=\\s*(\\d+|0x\\d\\d)', str) = 1;

  除了 c1 為 2 或 5 的兩行以外,其它行都不包含數值的賦值,因此不會出現在結果中:


C1          STR
----------- -------------------------
          2 variable = 1234;
          5 myVar = 0x00;

  2 record(s) selected. 
 

  改進性能

  盡管上面的函數按照預期的方式工作,但還可以改進它以獲得更佳的性能。注:函數內部的執行完成得越快,DB2 處理整個 SQL 語句的速度也就越快。

  SQL 旨在處理多組行,這意味着通常會針對一個模式匹配多個行。在大多數情況下,模式本身對於整個 SQL 語句都是不變的;即,它不會隨行的更改而更改。 清單 5 中的 C 代碼展示了對每一行都調用函數 pcre_compile() ,該函數將給定模式轉換成內部表示法。

  DB2 通過使用所謂的“高速暫存(scratchpad)”提供了在 UDF 調用之間傳遞信息的機制。此外,您可以標識特定調用“類型”;即它是對該 UDF 的第一次調用、普通調用還是最后一次(最終)調用。使用高速暫存和調用類型,有可能只對模式編譯一次,然后將該已編譯模式的內部表示法重用於對該 UDF 的所有后續調用。在最后一次調用時,釋放在處理期間分配的資源。

  如 清單 6所示,對 CREATE FUNCTION 語句進行修改,告訴 DB2 向外部 C 代碼提供高速暫存和調用類型:

  清單 6. 將高速暫存和調用類型添加到 CREATE FUNCTION 語句


CREATE FUNCTION regex2(pattern VARCHAR(2048), string CLOB(10M))
    RETURNS INTEGER
    SPECIFIC regexPerf
    EXTERNAL NAME 'regexUdf!regexpPerf'
    LANGUAGE C
    PARAMETER STYLE DB2SQL
    DETERMINISTIC
    NOT FENCED
    RETURNS NULL ON NULL INPUT
    NO SQL
    NO EXTERNAL ACTION
            SCRATCHPAD 50 FINAL CALL 
    ALLOW PARALLEL;
        

UDF 入口點看起來很不一樣,因為必須改寫函數內部的邏輯。參數方面唯一的更改是使用 SQLUDF_TRAIL_ARGS_ALL 代替了 SQLUDF_TRAIL_ARGS ,如 清單 7所示。

清單 7. regex2 的 C UDF 入口點


#include 
#include 

// data structure mapped on the scratchpad for easier use and access
// to the objects
// the size of the scratchpad defined in the CREATE FUNCTION statement
// must be at least as large as sizeof(scratchPadMapping)
struct scratchPadMapping {
    pcre *re;
    pcre_extra *extra;
    const char *error;
    int errOffset;
};

void regexpPerf(
    // input parameters
    SQLUDF_VARCHAR *pattern,      SQLUDF_CLOB *str,
    // output
    SQLUDF_INTEGER *match,
    // null indicators
    SQLUDF_NULLIND *pattern_ind,  SQLUDF_NULLIND *str_ind,
    SQLUDF_NULLIND *match_ind,
    SQLUDF_TRAIL_ARGS_ALL) // SQLUDF_SCRAT & SQLUDF_CALLT
{
    int rc = 0;
    struct scratchPadMapping *scratch = NULL;

    // map the buffer of the scratchpad and assume successful return
    scratch = (struct scratchPadMapping *)SQLUDF_SCRAT->data;
    *match_ind = 0;

    switch (SQLUDF_CALLT) {
      case SQLUDF_FIRST_CALL:
        // initialize data on the scratchpad
        scratch->re = NULL;
        scratch->extra = NULL;
        scratch->error = NULL;
        scratch->errOffset = 0;

        // compile the pattern (only in the FIRST call
        scratch->re = pcre_compile(pattern, 0 /* default options */,
            &scratch->error, &scratch->errOffset, NULL);
        if (scratch->re == NULL) {
            snprintf(SQLUDF_MSGTX, 70, "Regexp compilation failed at "
                "offset %d: %s\\n", scratch->errOffset, scratch->error);
            strcpy(SQLUDF_STATE, "38900");
            rc = -1;
            break;
        }

        // further analyze the pattern (might return NULL)
        scratch->extra = pcre_study(scratch->re,
            0 /* default options */, &scratch->error);

        /* fall through to NORMAL call because DB2 expects a result
           already in the FIRST call */

      case SQLUDF_NORMAL_CALL:
        // match the current string
        rc = pcre_exec(scratch->re, scratch->extra, str->data,
              str->length, 0, 0 /* default options */, NULL, 0);
        switch (rc) {
          case PCRE_ERROR_NOMATCH:
            *match = 0;
            rc = 0;
            break;
          case PCRE_ERROR_BADOPTION:
            snprintf(SQLUDF_MSGTX, 70, "An unrecognized bit was set "
                "in the options argument");
            strcpy(SQLUDF_STATE, "38901");
            rc = -1;
            break;
          case PCRE_ERROR_NOMEMORY:
            snprintf(SQLUDF_MSGTX, 70, "Not enough memory available.");
            strcpy(SQLUDF_STATE, "38902");
            rc = -1;
            break;
          default:
            if (rc < 0) {
                snprintf(SQLUDF_MSGTX, 70, "A regexp match error "
                    "occured: %d", rc);
                strcpy(SQLUDF_STATE, "38903");
                rc = -1;
            }
            else {
                *match = 1;
                rc = 0;
            }
            break;
        }
        break;
      }

      // cleanup in FINAL call, or if we encountered an error in
      // the FIRST call (DB2 will make a FINAL call if we encounter
      // an error in any NORMAL call)
      if (SQLUDF_CALLT == SQLUDF_FINAL_CALL ||
          (SQLUDF_CALLT == SQLUDF_FIRST_CALL && rc < 0)) {
          (*pcre_free)(scratch->re);
          (*pcre_free)(scratch->extra);
      }
      return;
}

  為了進一步改進該函數的性能,我添加了對函數 pcre_study() 的調用,該函數是由模式匹配引擎提供的。該函數進一步分析了該模式,並將額外的信息存儲在獨立的結構中。然后,在實際的匹配期間使用這些額外的信息來加快處理速度。通過使用一個非常簡單的模式和大約 4000 行的表,我獲得了 5% 的執行時間的改善。當然,模式越復雜,差異將越顯著。 #p#先前提到該實現假定模式在處理期間不會隨行的不同而更改。當然,如果模式確實更改了,您可以進行少量的改寫以再次編譯一個模式。要這樣做,有必要跟蹤當前(已編譯的)模式並在每次調用中將它與所提供的模式進行比較。也可以在高速暫存中維護當前模式。但必須將它復制到獨立的緩沖區,並且不能通過指針模式直接引用它,因為這個指針或它所引用的數據可能會更改或變為無效。至於相應的代碼更改,就當作練習留給讀者了。

  返回匹配子串

  大多數模式匹配引擎提供了一種方法,返回與指定模式或其一部分相匹配的子串。如果想在 SQL 中使用這種能力,則必須使用不同的方法來實現匹配函數。給定的字符串可能包含不止一個匹配的子串。例如,當解析類似“abc = 123;”或“def = 'some text';”這樣的字符串時,用戶可能會希望檢索由等號分隔的兩個子串。您可以使用模式“\\w+\\s*=\\s*(\\d+|'[\\w\\s] *');”來表示適用於該字符串的語法規則。Perl 兼容的正則表達式允許您捕獲等號兩邊的子串。最后,必須將要捕獲的子串用括號括起來。我已經用該方式編寫了第二個子串,但第一個子串不是這樣編寫的。用於該用途的最終模式是這樣的:

   
(\\w+)\\s*=\\s*(\\d+|'[\\w\\s]*');

  當把這個模式應用於字符串“abc= 123;”或“def = 'some text';”時,“abc”或“def”分別與“(\\w+)”匹配,空格和等號是通過“\\s*=\\s*”查找的,並用另外的“(\\d+|'[\ \w\\s*]')”涵蓋了余下的子串。在“(\\d+|'[\\w\\s*]')”中,第一個選項與任何至少由一個數字“\\d+”組成的數匹配,而第二個選項解析任何由字母和空格組成的由單引號括起的字符串“'[\\w\\s]*'”。

  在 DB2 中做到這一點的需求可以描述成:為一次 UDF 調用返回多個結果。換句話說,就是返回針對模式進行匹配的單個字符串的多個子串。DB2 的表函數是完成這一任務的完美工具。

  實現表 UDF

  和以前一樣,必須在數據庫中創建該函數。 清單 8中的下列語句正是用於這一任務的:

清單 8. 注冊名為 regex3 的表 UDF


CREATE FUNCTION regex3(pattern VARCHAR(2048), string CLOB(10M))
    RETURNS TABLE ( position INTEGER, substring VARCHAR(2048) )
    SPECIFIC regexSubstr
    EXTERNAL NAME 'regexUdf!regexpSubstr'
    LANGUAGE C
    PARAMETER STYLE DB2SQL
    DETERMINISTIC
    NOT FENCED
    RETURNS NULL ON NULL INPUT
    NO SQL
    NO EXTERNAL ACTION
    SCRATCHPAD 50
    NO FINAL CALL
    DISALLOW PARALLEL;

  實現該函數的實際邏輯的 C 代碼與 清單 7中的代碼非常相似,但根據表函數所必須滿足的特殊需求對它進行了改編,如 清單 9所示。

  清單 9. 實現表函數將要使用的 regex3 函數


#include 
#include 
#include 
#include 

struct scratchPadMapping {
    pcre *re;
    pcre_extra *extra;
    const char *error;
    int errOffset;
    int numSubstr;
    int *substr;
    int currentSubstr;
};

void regexpSubstr(
    // input parameters
    SQLUDF_VARCHAR *pattern,      SQLUDF_CLOB *str,
    // output
    SQLUDF_INTEGER *pos,          SQLUDF_VARCHAR *substr,
    // null indicators
    SQLUDF_NULLIND *pattern_ind,  SQLUDF_NULLIND *str_ind,
    SQLUDF_NULLIND *pos_ind,      SQLUDF_NULLIND *substr_ind,
    SQLUDF_TRAIL_ARGS_ALL) // SQLUDF_SCRAT & SQLUDF_CALLT
{
    int rc = 0;
    size_t length = 0;
    struct scratchPadMapping *scratch = NULL;

    // map the buffer of the scratchpad and assume NULL return
    scratch = (struct scratchPadMapping *)SQLUDF_SCRAT->data;
    *pos_ind = 0;
    *substr_ind = 0;

    switch (SQLUDF_CALLT) {
      case SQLUDF_TF_OPEN:
        // initialize data on the scratchpad
        scratch->re = NULL;
        scratch->extra = NULL;
        scratch->error = NULL;
        scratch->errOffset = 0;
        scratch->numSubstr = 0;
        scratch->substr = NULL;
        scratch->currentSubstr = 1; // skip the complete match

        // compile the pattern (only in the FIRST call
        scratch->re = pcre_compile(pattern, 0 /* default options */,
            &scratch->error, &scratch->errOffset, NULL);
        if (scratch->re == NULL) {
            snprintf(SQLUDF_MSGTX, 70, "Regexp compilation failed at "
                "offset %d: %s\\n", scratch->errOffset, scratch->error);
            strcpy(SQLUDF_STATE, "38900");
            rc = -1;
            break;
        }
        // further analyze the pattern (might return NULL)
        scratch->extra = pcre_study(scratch->re,
            0 /* default options */, &scratch->error);
        // determine the number of capturing subpatterns
        rc = pcre_fullinfo(scratch->re, scratch->extra,
            PCRE_INFO_CAPTURECOUNT, &scratch->numSubstr);
        if (rc) {
            snprintf(SQLUDF_MSGTX, 70, "Could not retrieve info "
                "on pattern. (rc = %d)", rc);
            strcpy(SQLUDF_STATE, "38901");
            rc = -1;
            break;
        }
        // allocate memory for the substring indices
        {
            int size = (scratch->numSubstr+1)*3;
            scratch->substr = (int *)malloc(size * sizeof(int));
            if (!scratch->substr) {
                snprintf(SQLUDF_MSGTX, 70, "Could allocate memory for "
                    "substring indices.");
                strcpy(SQLUDF_STATE, "38902");
                rc = -1;
                break;
            }
            memset(scratch->substr, 0, size * sizeof(int));
            // match the current string
            rc = pcre_exec(scratch->re, scratch->extra, str->data,
            str->length, 0, 0 /* default options */,
                scratch->substr, size);
        }
        switch (rc) {
          case PCRE_ERROR_BADOPTION:
            snprintf(SQLUDF_MSGTX, 70, "An unrecognized bit was set "
                "in the options argument");
            strcpy(SQLUDF_STATE, "38903");
            rc = -1;
            break;
          case PCRE_ERROR_NOMEMORY:
            snprintf(SQLUDF_MSGTX, 70, "Not enough memory available.");
            strcpy(SQLUDF_STATE, "38904");
            rc = -1;
            break;
          case PCRE_ERROR_NOMATCH:
            scratch->currentSubstr = scratch->numSubstr + 1;
            rc = 0;
            break;
          default:
            if (rc < 0) {
                snprintf(SQLUDF_MSGTX, 70, "A regexp match error "
                    "occured: %d", rc);
                strcpy(SQLUDF_STATE, "38905");
                rc = -1;
                break;
            }
        }
        break;

      case SQLUDF_TF_FETCH:
        // skip capturing substrings without a match
        while (scratch->currentSubstr <= scratch->numSubstr &&
            (scratch->substr[2*scratch->currentSubstr] < 0 ||
                scratch->substr[2*scratch->currentSubstr+1] < 0)) {
            scratch->currentSubstr++;
        }
        // no more data to be returned
        if (scratch->currentSubstr > scratch->numSubstr) {
            strcpy(SQLUDF_STATE, SQL_NODATA_EXCEPTION);
            rc = 0;
            break;
        }
        // get the current substring
        *pos = scratch->currentSubstr;
        length = scratch->substr[2*scratch->currentSubstr+1] -
            scratch->substr[2*scratch->currentSubstr];
        strncpy(substr, str->data + scratch->substr[2*scratch->currentSubstr],
            length);
        substr[length] = '\\0';
        scratch->currentSubstr++;
    }

    // cleanup in CLOSE call, or if we encountered an error in
    // the OPEN call (DB2 will make a CLOSE call if we encounter
    // an error in any FETCH call)
    if (SQLUDF_CALLT == SQLUDF_TF_CLOSE ||
        (SQLUDF_CALLT == SQLUDF_TF_OPEN && rc < 0)) {
        (*pcre_free)(scratch->re);
        (*pcre_free)(scratch->extra);
        free(scratch->substr);
    }
    return;
}

  正如我們對基本匹配函數所做的那樣,您也可使用 FINAL CALL 定義表函數來改進性能。必須修改 C 代碼以處理 SQLUDF_TF_FIRST 和 SQLUDF_TF_FINAL 調用。

  用法示例

  表函數可以在類似於如下所示的 SELECT 語句中使用:


SELECT c1, str, num, substr
FROM   strTable,
       TABLE ( regex3('(\\w+)\\s*=\\s*(\\d+|''[\\w\\s]*'');', str) ) AS sub(num, substr)

  結果只包括擁有匹配模式的字符串。對於每個字符串,都在單獨的行中顯示所捕獲的第一個和第二個子串。


C1          2                              NUM         4
----------- ------------------------------ ----------- -----------------------
          2 variable = 1234;                         1 variable
          2 variable = 1234;                         2 1234
          3 var2 = 'string variable';                1 var2
          3 var2 = 'string variable';                2 'string variable'

  4 record(s) selected.

  下一個查詢在結果集中用單獨的列而不是單獨的行返回這兩個子串對。這樣,用 SQL 語句進一步處理這些字符串以及它們的子串要容易些。該查詢使用了公共表表達式(由關鍵字 WITH 表示)來確保在整個查詢中只對每個字符串進行一次求值,而不是在中間表 s1s2 所需的每次子選擇中都進行一次求值。


WITH substrings(c, num, substr) AS
   ( SELECT c1, num, substr
     FROM   strTable,
            TABLE ( regex3('(\\w+)\\s*=\\s*(\\d+|''[\\w\\s]*'');', str) )
               AS sub(num, substr) )
SELECT t.c1, s1.substr AS variable, s2.substr AS value
FROM   strTable AS t JOIN substrings AS s1 ON
          ( t.c1 = s1.c ) JOIN
       substrings AS s2 ON
          ( t.c1 = s2.c )
WHERE  s1.num = 1 AND s2.num = 2

  這里使用了與前面查詢中相同的模式。因此,可以從上面的表中派生出結果,但這一次,根據請求,這些 variable-value 對每個都位於單獨的行中。


C1          VARIABLE                       VALUE
----------- ------------------------------ --------------------
          2 variable                       1234
          3 var2                           'string variable'

  2 record(s) selected. 

  結束語

  UDF 可以用來以兩種形式在 DB2 中提供正則表達式。在第一種形式中,通過將字符串與給定模式進行比較來完成基本匹配。第二種形式是實現表函數,它從正則表達式抽取已捕獲的子串,並將這些子串返回給 DB2,以便用在 SQL 語句的進一步處理中。我還給出了一些關於如何改進性能的提示。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM