前言
在數據庫程序開發中,經常遇到的一種情形是特定格式的字符串存儲了應以行方式表現的數據集合。下面的查詢結果是這種情形的一個樣本。
清單 1. 查詢 DB2 系統目錄視圖 SYSCAT.CHECKS
SELECT func_path FROM syscat.checks;
FUNC_PATH
--------------------------------------------------------
"SYSIBM","SYSFUN","SYSPROC","STOLZE"
"SYSIBM","SYSFUN","SYSPROC","MYSCHEMA"
"SYSIBM","SYSFUN","SYSPROC"
"SYSIBM","SYSFUN","SYSPROC"
4 record(s) selected.
可以很容易地觀察出在上面的結果集合中。字符串存儲了以逗號為分割符號的多個元素。為了較為方便地使用這些元素,常常需要對字符串進一步的解析和處理,從而轉變為如下的表現形式。
注:僅解析"SYSIBM","SYSFUN","SYSPROC","STOLZE"
FUNC_PATH
------------------------------------------
"SYSIBM"
"SYSFUN"
"SYSPROC"
"STOLZE"
在傳統過程性開發語言中,例如 C 或者 Java 語言中,如果不利用系統函數(類)而是自己編寫字符串函數(類)的話,其原理通常是利用 FOR 循環或遞歸迭代方式。
利用同樣的原理,在數據庫中亦可利用擴展 SQL 編寫函數來完成字符串解析,不能說這是一種很理想的解決方案。相對 SQL 的編寫/調試來說,函數的編寫/調試是較為復雜的一種技術。而且由於函數以及函數內采用的特定技術的原因,這種方案不能很好地在不同的數據庫環境中移植。本文將采用一種純 SQL 的解決方案即利用輔助表格編寫標准的 SQL 語句來完成標准格式字符串的解析,並利用這種方式完成一個衍生應用。
場景准備
在進一步闡述新方式之前,我們要建立簡單的場景:即樣本表格和用於觀察及測試的數據。這個清單及其數據被用於下面的所有示例。
清單 2. 創建表並插入示例數據
CREATE TABLE strings (
id INTEGER NOT NULL PRIMARY KEY,
str VARCHAR(128) NOT NULL
);
INSERT INTO strings VALUES ( 1,'ab,c,d,123' ),
( 2,'123,456789,abc,123' ),( 3,'a,b,c,d' ),
( 4,'string' );
SELECT * FROM strings;
ID STR
----------- ----------------------
1 ab,c,d,123
2 123,456789,abc,123
3 a,b,c,d
4 string
4 record(s) selected.
可以確定的是,對字符串進行解析的前提是可以獲取字符串中的所有字符,在區分出字符分割符位置的基礎之上進行多個元素的界定。下面的表格是對編號為 1 的字符串進行手工字符解析的結果。
列表 1:對編號為 1 的字符串進行解析
字符串 字符位置 字符 是否分割符
ab,c,d,123 1 a ×
ab,c,d,123 2 b ×
ab,c,d,123 3 , √
ab,c,d,123 4 c ×
ab,c,d,123 5 , √
ab,c,d,123 6 d ×
ab,c,d,123 7 , √
ab,c,d,123 8 1 ×
ab,c,d,123 9 2 ×
ab,c,d,123 10 3 ×
觀察列表 1 可以發現,字符可以由字符串和字符位置推導出來。但僅僅通過表格 STRINGS 是無法提供"字符串"和"字符位置"這樣的結果集合的。想像一下,如果存在一個存儲從 1 到字符串長度的數據序列表格,那麼可以把"字符串"和"字符位置"這樣的結果集視為字符串和數據序列表格的一個笛卡爾集。
這個序列表格就是標題中所述的輔助表格,在它的幫助之下,對每一個字符進行解析都成了可能。對輔助表格的要求是存儲足夠大,內容是從一開始的連續數據序列。下面是建立這個輔助表格的腳本。
清單 3 創建序列表並插入示例數據
CREATE TABLE numSerial (
id INTEGER NOT NULL PRIMARY KEY
)