在WEB查詢中,我們一般將大量數據分切成頁,一頁一頁地推送給BROWER端。另外,基本表信息中又大量使用字典表,如果將這些數據與字典表關聯,將會極大加重服務器的重擔。
如有一個記錄均超過100W以上記錄的A表,裏面有一個A1,A2,A3,A4這四個字段,表示某個字典的代碼,爲了關聯出與它們對應的代碼意義(設它們的字典分別爲D_A1,D_A2,D_A3,D_A4),你可以這樣寫相關的SELECT-SQL,
Select a.*,a1.a1_NAME,a2.a2_NAME,a3.a3_NAME,a4.a4_NAME From A Left join D_a1 a1 on A.a1=A1.A1 Left join D_a2 a2 on A.a2=A2.A2 Left join D_a3 a3 on A.a3=A3.A3 Left join D_a4 a4 on A.a4=A4.A3
此SQL當然沒有什麼錯誤,而且也能關聯出結果。但問題是:在100W以上的記錄上去關聯字典表(如果字典表也比較大的話),這會是一個很耗時的查詢。下面給出一個優化SQL(每頁25條記錄,顯示滿足條件的第二頁):
select t.*, a.字典名1, a.字典名2 from ( SELECT t.* FROM (select a.*, rownumber() over() AS MyTempRecordeNo from [你要查詢的表] a Where [你的條件] ) t WHERE t.MyTempRecordeNo BETWEEN 26 AND 50 ) t left join [字典表1] a ON 相關條件1 left join [字典表2] b ON 相關條件2 with ur
使用存儲過程的通用分頁方式:
CREATE PROCEDURE DB2ADMIN.PROC_GETPAGE
(INOUT CURRENTPAGE INTEGER,
IN STRSQL VARCHAR(500),
IN PAGESIZE INTEGER,
OUT TOTALPAGE INTEGER,
OUT TOTALRECORD INTEGER
)
SPECIFIC DB2ADMIN.SQL080201103307110
DYNAMIC RESULT SETS 1
LANGUAGE SQL
NOT DETERMINISTIC
CALLED ON NULL INPUT
READS SQL DATA
INHERIT SPECIAL REGISTERS
BEGIN
DECLARE tmpsql VARCHAR(1000); -- 主語句
DECLARE orderFiled VARCHAR(50);
DECLARE s VARCHAR(1000);
DECLARE v_Start INTEGER;
DECLARE v_End INTEGER;
DECLARE result CURSOR WITH RETURN TO CALLER FOR S2;
SET orderFiled =getOrderField(strsql);
if(length(orderFiled )>0) then
set orderFiled =' order by ' || orderFiled ;
end if;
SET s =getSQL(strsql);
set tmpsql = 'select count(*) from (' || strsql || ') as a';
prepare s2 from tmpsql;
open result;
fetch result into totalrecord;-- 總記錄數
close result;
if(pagesize = 0) then
set pagesize = 20;-- 每頁顯示數
end if;
set totalPage = (totalrecord - 1) / pagesize + 1;-- 總頁數
if(currentPage < 1) then
set currentPage = 1;-- 當前頁
else
if(currentPage > totalPage) then
set currentPage = totalPage;
end if;
end if;
set v_Start = (currentPage-1) * pagesize ;
set v_End = currentPage * pagesize;
set tmpsql ='select * from ' ||
'(select rownumber() over() as row, ' ||
'w.* from ( select * from ( ' || s || ') n ' || orderFiled || ') w) w1 where row between ' || char(v_Start ) || ' and ' || char(v_End );
prepare s2 from tmpsql ;
open result;
END;
使用了兩個java函數import java.util.regex.*;import COM.ibm.db2.app.UDF;public class FunctionDB2 extends UDF
{
public static String getOrderField(String sql)
{
Pattern Regex = Pattern.compile("select(.+)order\\s*by\\s*(.+)",
Pattern.CANON_EQ | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
Matcher RegexMatcher = Regex.matcher(sql);
if (RegexMatcher.find()) {
return RegexMatcher.group(2);
}
return "";
}
public static String getSQL(String sql)
{
Pattern Regex = Pattern.compile("(.+)order\\s*by\\s*(.+)",
Pattern.CANON_EQ | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
Matcher RegexMatcher = Regex.matcher(sql);
if (RegexMatcher.find()) {
return RegexMatcher.group(1);
}
return sql;
}
}
另外的通用分頁存儲過程:CREATE PROCEDURE SALES.DB2PAGINATION(IN ITBNAME VARCHAR(2000),-- 表名
IN ISHOWFIELD VARCHAR(1000),-- 顯示字段
IN IJOIN VARCHAR(1000),-- 聯接條件(如:內聯、外聯)
IN IWHERE VARCHAR(2000),-- 查詢條件 (注意: 不要加 WHERE)
IN IORDER VARCHAR(100),-- 排序條件 (注意: 不要加 ORDER BY)
IN IPAGESIZE INTEGER,-- 頁尺寸 如果爲0 默認返回前一百萬條數據可以認爲是返回所有數據
INOUT IOCURRENTPAGEIX INTEGER,-- 輸入和輸出:當前頁
OUT OPAGESTARTROW INTEGER,-- 輸出:當前開始行
OUT OPAGEENDROW INTEGER,-- 輸出:當前結束行
OUT OTOTALROWS INTEGER,-- 輸出:當前總記錄數
OUT OHASPREVIOUSPAGE INTEGER,-- 輸出:是否有上一頁
OUT OHASNEXTPAGE INTEGER,-- 輸出:是否有下一頁
OUT OTOTALPAGES INTEGER,-- 輸出:總頁數
OUT OERROR VARCHAR(100))-- 輸出:錯誤信息
RESULT SETS 1
MODIFIES SQL DATA
NOT DETERMINISTIC
LANGUAGE SQL
BEGIN
/**//*----------------------------------------------------------------
* Copyright (C) 2007 Huacius
* 版權所有。
*
* 存儲過程分頁
*
*
//-----------------------------------------------------------------------*/
DECLARE STRSQL VARCHAR(6000);-- 主語句DECLARE result CURSOR WITH RETURN TO CALLER FOR S2;DECLARE exit handler FOR sqlexception-- 異常捕獲
BEGIN
set OERROR = 'error!';
END;-- BODY start --
if(iwhere <> '') then
set iwhere = ' where ' || iwhere;
end if;
if(iorder <> '') then
set iorder = 'order by ' || iorder;
end if;
if(ijoin <> '') then
set ijoin = ' ' || ijoin;
end if;
set strsql = 'select count(*) from ' || itbname || ijoin || iwhere;
prepare s2 from strsql;
open result;
fetch result into ototalrows;-- 總記錄數
close result;if(ipagesize = 0) then
set ipagesize = 1000000;-- 每頁顯示數
end if;set ototalpages = (ototalrows - 1) / ipagesize + 1;-- 總頁數if(iocurrentpageix < 1) then
set iocurrentpageix = 1;-- 當前頁
else
if(iocurrentpageix > ototalpages) then
set iocurrentpageix = ototalpages;
end if;
end if;set opagestartrow = ipagesize * (iocurrentpageix -1) + 1;-- 每頁開始數
if(iocurrentpageix = ototalpages) then
set opageendrow = ototalrows;-- 每頁結束數
else
set opageendrow = ipagesize * iocurrentpageix;
end if;if(iocurrentpageix > 1) then
set ohaspreviouspage = 1;-- 是否有上一頁
else
set ohaspreviouspage = 0;
end if;if(iocurrentpageix < ototalpages) then
set ohasnextpage = 1;-- 是否有下一頁
else
set ohasnextpage = 0;
end if;set strsql = 'select * from (select rownumber() over(' || iorder || ') as rownum,'
|| ishowfield
|| ' from '
|| itbname
|| ijoin
|| iwhere
|| ') as temp where rownum between ' || rtrim(char(opagestartrow)) || ' and '|| rtrim(char(opageendrow));
prepare s2 from strsql;
open result;
-- BODY end --END
DB2存儲過程分頁測試CREATE PROCEDURE TEST ( IN IN_START SMALLINT,
IN IN_SIZE SMALLINT )
DYNAMIC RESULT SETS 1
------------------------------------------------------------------------
-- DB2下通過傳遞參數控制顯示記錄的範圍-- SQL 存儲過程
-- IN_START 記錄起點
-- IN_SIZE 記錄條數
------------------------------------------------------------------------
P1: BEGIN
-- 聲明遊標
DECLARE cursor1 CURSOR WITH RETURN FOR
SELECT *
FROM (SELECT ROW_NUMBER() OVER() as ROW_NO, T.* FROM TOPICIS.DM_HY AS T) AS TEMP
WHERE TEMP.ROW_NO > IN_START
AND TEMP.ROW_NO < IN_START + IN_SIZE;OPEN cursor1;
END P1DB2分頁查詢
SELECT * FROM (Select 字段1,字段2,字段3,rownumber() over(ORDER BY 排序用的列名 ASC) AS rn from 表名) AS a1 WHERE a1.rn BETWEEN 10 AND 20以上表示提取第10到20的紀錄select * from (select rownumber() over(order by id asc ) as rowid from table where rowid <=endIndex ) AS a1
where a1.rowid > startIndexDB2 SQL查詢結果集自動編號、返回條數範圍控制研究
摘要:DB2 SQL語句實現查詢的記錄自動編號、並根據編號進一步實現記錄範圍控制、分頁查詢。環境:IBM DB2 Universal V9.1Windows XP Professional要求:寫一個SQL語句,在查詢結果中要顯示出記錄序號,這個序號是是根據記錄順序自動生成的。測試初始化DB2 SQL腳本:drop table t_test;create table t_test(bs bigint not null not null generated by default as identity,username varchar(20) not null,password varchar(20),remark varchar(200));comment on t_test(bs is '標識',username is '用戶名',password is '密碼',remark is '備註');insert into t_test(username, password) values ('aaa', 'aaa'),('bbb', 'bbb'),('ccc', 'ccc'),('ddd', 'ddd'),('eee', 'eee'),('fff', 'fff'),('ggg', 'ggg');實現:1、實現查詢記錄編號要求:查詢bs不等於1的所有記錄。select t.*, ROW_NUMBER() OVER() as ROW_NOfrom t_test twhere t.bs <> 1查詢結果如下:bs username password remark ROW_NO---------------------------------------2 'bbb' 'bbb' '[Null]' 13 'ccc' 'ccc' '[Null]' 24 'ddd' 'ddd' '[Null]' 35 'eee' 'eee' '[Null]' 46 'fff' 'fff' '[Null]' 57 'ggg' 'ggg' '[Null]' 6說明:ROW_NUMBER() OVER() 是用來產生編號序列,從1開始編號,爲整數。as ROW_NO 是爲編號列設定顯示名稱。2、實現按照記錄範圍進行查詢要求:要求查詢第2-5條記錄。select *from (select t.*, ROW_NUMBER() OVER() as ROW_NOfrom t_test t) as wwhere ROW_NO >= 2and ROW_NO <=5查詢結果如下:bs username password remark ROW_NO---------------------------------------2 'bbb' 'bbb' '[Null]' 23 'ccc' 'ccc' '[Null]' 34 'ddd' 'ddd' '[Null]' 45 'eee' 'eee' '[Null]' 53、實現SQL分頁查詢對2中的SQL進行擴展,將範圍起始編號作爲變量傳遞給SQL就可以實現分頁查詢了。當然這個還需要程序的支持,掌握這個原理就很容易了,在此不做介紹。總結:對記錄返回控制是數據庫系統的特性,不同的數據庫系統有不同的實現。SQL直接對結果集記錄控制效率上一般是最好的。結合高級編程語言,可以實現複雜的分頁查詢。DB2 SQL TOP 解決方式:我們都知道在sql server中的如下sql語句是正確的
select top 20 * from tablename order by id desc
而在DB2中,這句話就存在問題了,系統會報錯。解決方法如下:
select * from tablename order by id desc fetch first N rows only
這樣就可以了我的語句是strSQL = "select CostBill_Master.*,GT_USERINFO.USRNAM from CostBill_Master,GT_USERINFO where CostBill_Master.DPTIDT='"+branchId+"' and GT_USERINFO.USRIDT=CostBill_Master.USERIDT order by BillNo desc fetch first 10 rows only";