CREATE PROCEDURE KYJT.USP_A_FY (
IN PTBLNAME VARCHAR(1000), -- 表名
IN PSHOWNAME VARCHAR(1000), -- 顯示欄位清單
IN PFLDNAME VARCHAR(1000), -- 主鍵欄位(唯一、非重複)
IN PPAGESIZE INTEGER, -- 頁大小(0=預設 1000 萬,相當於全表)
IN PPAGEINDEX INTEGER, -- 頁碼(1-based)
IN PORDERTYPE INTEGER, -- 排序:非 0=降序,0=升序
IN PSTRWHERE VARCHAR(1000) -- WHERE 條件(不含 WHERE 關鍵字)
)
MODIFIES SQL DATA
DETERMINISTIC
LANGUAGE SQL
採用鍵值範圍定位 + FETCH FIRST 技巧,避免傳統 OFFSET 掃描大量前置資料列的效能問題。
PORDERTYPE 決定排序方向與比較運算子:
WHERE pk > (SELECT MAX(pk) FROM (SELECT pk FROM tbl ORDER BY pk ASC FETCH FIRST (page-1)*size ROWS ONLY) AS tmp)WHERE pk < (SELECT MIN(pk) FROM (SELECT pk FROM tbl ORDER BY pk DESC FETCH FIRST (page-1)*size ROWS ONLY) AS tmp)ORDER BY ... FETCH FIRST size ROWS ONLY,無需巢狀子查詢。PREPARE → OPEN CURSOR WITH RETURN TO CALLER 回傳結果集。-- 排序與比較邏輯建構
IF (PORDERTYPE <> 0) THEN
SET C_STRTMP = '<(SELECT MIN';
SET C_STRORDER = ' ORDER BY ' || PFLDNAME || ' DESC';
ELSE
SET C_STRTMP = '>(SELECT MAX';
SET C_STRORDER = ' ORDER BY ' || PFLDNAME || ' ASC';
END IF;
-- 一般頁面動態 SQL
SET C_STRSQL = 'SELECT ' || PSHOWNAME || ' FROM ' || PTBLNAME ||
' WHERE ' || PFLDNAME || ' ' || C_STRTMP ||
'(TBLTMP.TTT) FROM (SELECT ' || PFLDNAME || ' AS TTT FROM ' || PTBLNAME ||
' ' || C_STRORDER || ' FETCH FIRST ' || CHAR((PPAGEINDEX-1)*PPAGESIZE) || ' ROWS ONLY) AS TBLTMP)' ||
C_STRORDER || ' FETCH FIRST ' || CHAR(PPAGESIZE) || ' ROWS ONLY';
-- 第 1 頁優化路徑
IF (PPAGEINDEX = 1) THEN
SET C_STRSQL = 'SELECT ' || PSHOWNAME || ' FROM ' || PTBLNAME ||
(CASE WHEN PSTRWHERE <> '' THEN ' WHERE ' || PSTRWHERE ELSE '' END) ||
' ' || C_STRORDER || ' FETCH FIRST ' || CHAR(PPAGESIZE) || ' ROWS ONLY';
END IF;
| 優勢 | 限制/注意事項 |
|---|---|
| 避免 OFFSET 掃描,大頁碼效能不衰減 | 要求 PFLDNAME 為唯一且有索引,否則結果不確定 |
| 動態 SQL 靈活支援任意表/欄位/條件 | 動態 SQL 需編譯開銷,高頻呼叫建議改為靜態游標或應用層分頁 |
| 游標回傳,支援 JDBC/CLI/ODBC 串流讀取 | VARCHAR(1000) 參數長度限制複雜查詢,大型條件需拆分 |
| 第 1 頁走最優路徑 | SQL 注入風險:參數直接拼接,生產環境需嚴格驗證或改用參數化動態 SQL |
DBMS_ASSERT 驗證識別字元,或改寫為參數化 PREPARE(DB2 9.7+ 支援)。PPAGESIZE/PPAGEINDEX 建議加上 CHECK (val > 0) 邏輯。OFFSET ... LIMIT / FETCH FIRST ... ROWS ONLY 標準語法,簡化邏輯。此存儲過程展示了 DB2 SQL PL 動態 SQL 與游標回傳的經典組合,理解其原理有助於在現代版本中設計更優雅的分頁方案。