利用Oracle儲存過程實現中國式的交叉統計報表

2021-05-22 21:56:56 字數 4479 閱讀 1607

很多時候,我們需要做一些中國式的報表,例如:我們有一下幾張資料表來表示某大學,對各個省份的招生計畫資訊:

省份資訊表

area_id名稱1

遼寧2吉林3

黑龍江……

專業資訊表

speciality_id

院系名稱

1外語系

2計算機系

3中文系……

招生計畫資訊表

area_id

speciality_id

年度招生人數11

201032

1201053

1201031

2201022

2201053

2201031

3201012

3201043

320105…

………

那麼我們想要統計乙個交叉的報表,統計2023年度,每個專業在各個省份的招生人數,即下面這個交叉統計報表(中國式報表):

本年度各個專業在各個省份的招生計畫資訊

外語系計算機系

中文系遼寧32

1吉林55

4黑龍江33

5………

下面我們使用乙個儲存過程來實現此型別的報表統計,由於我們首先需要取得此大學院系資料游標,並通過迴圈此游標生成乙個二次查詢統計的sql語句,此sql在生成之後會十分龐大,可能會超過oracle中varchar2的長度限制(32767)。所以此儲存過程採用dbms_sql.varchar2s字串陣列來實現動態sql。

但是問題又出現了,由於dbms_sql.varchar2s執行動態sql之後無法返回乙個游標,所以當dbms_sql.varchar2s執行sql時我們考慮使用view來完成此功能,也就是說,通過dbms_sql.varchar2s執行之後會生成乙個我們需要的臨時檢視view,然後我們再通過普通的sql去查詢此檢視,並返回游標。具體的儲存過程實現如下:

create

orreplace

procedure p_queryreport(h_tablename

invarchar2 ,

--行表名

h_fieldcode

invarchar2 ,

--行編碼

h_fieldname

invarchar2 ,

--行名稱

h_sqlwhere  

invarchar2 ,

--行查詢條件從and開始

l_tablename

invarchar2 ,

--列表名

l_fieldcode

invarchar2 ,

--列編碼

l_fieldname

invarchar2 ,

--列名稱

l_sqlwhere  

invarchar2 ,

--列查詢條件

c_tablename    

invarchar2 ,

--統計表名

c_sum_fieldcode

invarchar2 ,

--彙總欄位名

c_h_fieldcode  

invarchar2 ,

--統計表關聯行編碼

c_l_fieldcode  

invarchar2 ,

--統計表關聯列編碼

c_sqlwhere      

invarchar2 ,

--統計表查詢條件

resultlist

out sys_refcursor

--返回結果集

) authid current_user

isl_sql    

varchar2 (32767);

l_rs     sys_refcursor;

l_r_code

varchar2 (32767);

l_r_name

varchar2 (32767);

h_sql

varchar2 (32767);

p_c_sqlwhere

varchar (32767);

------------------------------------------

l_stmt  

dbms_sql .varchar2s;

l_cursor

integer

default

dbms_sql .open_cursor;

l_rows  

number

default 0;

l_length

number := 0;

i        

number := 1;

e        

number := 0;

--------------------------------------------

begin

p_c_sqlwhere := c_sqlwhere;

e :=

length (p_c_sqlwhere);

l_stmt(i) :=

'create or replace view lhtempview as select ' ||

h_fieldcode ||

',' || h_fieldname ||

',' ;

i := i + 1;

l_sql :=

'select ' || l_fieldcode ||

',' || l_fieldname ||

' from ' ||

l_tablename ||

' where 1=1 ' || trim(l_sqlwhere) ||

' ' ;

open l_rs

for l_sql;

loop

fetch l_rs

into l_r_code, l_r_name;

exit

when l_rs%notfound;

l_stmt(i) :=

' (select sum(' || c_sum_fieldcode ||

')  from ' ;

i := i + 1;

l_stmt(i) := c_tablename;

i := i + 1;

l_stmt(i) :=

' where ' ;

i := i + 1;

l_stmt(i) := c_l_fieldcode;

i := i + 1;

l_stmt(i) :=

' = '

'' || l_r_code ||

''' ' ;

i := i + 1;

l_stmt(i) := trim(p_c_sqlwhere);

i := i + 1;

l_stmt(i) :=

' and ' || c_h_fieldcode ||

' = ' || h_fieldcode ||

') as "' || l_r_name ||

'_' || i ||

'",' ;

i := i + 1;

endloop ;

if i > 2

then

l_stmt(i - 1) :=

substr (l_stmt(i - 1), 0,

length (l_stmt(i - 1)) - 1);

endif ;

l_stmt(i) :=

' from ' || h_tablename ||

' where 1=1 ' || trim(h_sqlwhere);

l_sql := l_stmt(i - 1);

dbms_sql .

parse (c             => l_cursor,

statement      => l_stmt,

lb            => l_stmt.first,

ub            => l_stmt.last,

lf***         =>

true ,

language_flag =>

dbms_sql .native);

l_rows :=

dbms_sql .

execute (l_cursor);

dbms_sql .

close_cursor (l_cursor);

h_sql :=

'select * from lhtempview' ;

open resultlist

for h_sql;

end p_queryreport;

利用儲存過程實現資料分頁

利用ms sql2000的儲存過程實現資料分頁讀取,可簡化讀取的資料量。本過程的優點在於,輸入的sql語句沒有限制條件,而且寫法和思路都很簡單明瞭。create procedure dbo pageshow sql varchar 8000 where語句 pagesize int 10,每頁的大小...

oracle儲存過程實現分頁

建立儲存過程 建立存放游標的包 create or replace package page package is 申明游標 type page cursor is ref cursor end page package 建立查詢所有使用者的過程 create or replace procedur...

oracle 儲存過程實現分頁

1 create or replace package pkg query is23 45 author administrator 6 created 2016 12 8 星期四 10 28 37 7 purpose 用做查詢游標89 10 public type declarations 11 ...