|
我现在就来示范一下,改用静态SQL之后27楼的程序可以变得如何整洁漂亮:
CREATE OR REPLACE FUNCTION fsql1(v_tname varchar2,tr varchar2 ,tc0 varchar2)
RETURN VARCHAR2
IS
lv_sql VARCHAR2(4000);
lv_name VARCHAR2(30);
BEGIN
SELECT cname2
INTO lv_name
FROM eav
WHERE tname = v_tname
AND cname = tr
AND ccode IS NULL;
lv_sql := 'WITH t AS (
SELECT '||tr||','||REPLACE(tc0,' ',',')||',COUNT(*) cnt FROM '||v_tname||' GROUP BY '||tr||','||REPLACE(tc0,' ',',')||')
,t1 AS (
SELECT '||tr||' AS '||lv_name;
FOR lv_rec IN (SELECT SYS_CONNECT_BY_PATH(cname||'='''||ccode||'''',' AND ') AS s1
,'C'||REPLACE(SYS_CONNECT_BY_PATH(cname2,','),',') AS s2
FROM
(SELECT e.*,t.id
FROM eav e
,(SELECT ROWNUM id, CAST(column_value AS VARCHAR2(30)) c
FROM xmltable(('"'||REPLACE(tc0,' ','","')||'"'))
) t
WHERE e.tname = v_tname
AND e.cname = t.c
AND e.ccode IS NOT NULL
) e2
WHERE CONNECT_BY_ISLEAF=1
START WITH id=1
CONNECT BY id = PRIOR id+1
ORDER SIBLINGS BY ccode
)
LOOP
lv_sql := lv_sql ||CHR(10)||' ,SUM(CAS WHEN '||SUBSTR(lv_rec.s1,5)||' THEN cnt END) AS '||lv_rec.s2;
END LOOP;
lv_sql := lv_sql ||CHR(10)||' FROM T GROUP BY '||tr||')
SELECT * FROM t1';
RETURN lv_sql;
END fsql1;
/
jsu@JSU> SELECT fsql1('tren','region','sex nation age class1') FROM DUAL;
FSQL1('TREN','REGION','SEXNATIONAGECLASS1')
----------------------------------------------------------------------------------------------------------------------------
WITH t AS (
SELECT region,sex,nation,age,class1,COUNT(*) cnt FROM tren GROUP BY region,sex,nation,age,class1)
,t1 AS (
SELECT region AS 地区
,SUM(CAS WHEN sex='F' AND nation='1' AND age='1' AND class1='1' THEN cnt END) AS C女汉1岁学生
,SUM(CAS WHEN sex='F' AND nation='1' AND age='1' AND class1='2' THEN cnt END) AS C女汉1岁工人
,SUM(CAS WHEN sex='F' AND nation='1' AND age='1' AND class1='3' THEN cnt END) AS C女汉1岁农民
,SUM(CAS WHEN sex='F' AND nation='1' AND age='2' AND class1='1' THEN cnt END) AS C女汉2岁学生
,SUM(CAS WHEN sex='F' AND nation='1' AND age='2' AND class1='2' THEN cnt END) AS C女汉2岁工人
,SUM(CAS WHEN sex='F' AND nation='1' AND age='2' AND class1='3' THEN cnt END) AS C女汉2岁农民
,SUM(CAS WHEN sex='F' AND nation='2' AND age='1' AND class1='1' THEN cnt END) AS C女壮1岁学生
,SUM(CAS WHEN sex='F' AND nation='2' AND age='1' AND class1='2' THEN cnt END) AS C女壮1岁工人
,SUM(CAS WHEN sex='F' AND nation='2' AND age='1' AND class1='3' THEN cnt END) AS C女壮1岁农民
,SUM(CAS WHEN sex='F' AND nation='2' AND age='2' AND class1='1' THEN cnt END) AS C女壮2岁学生
,SUM(CAS WHEN sex='F' AND nation='2' AND age='2' AND class1='2' THEN cnt END) AS C女壮2岁工人
,SUM(CAS WHEN sex='F' AND nation='2' AND age='2' AND class1='3' THEN cnt END) AS C女壮2岁农民
,SUM(CAS WHEN sex='M' AND nation='1' AND age='1' AND class1='1' THEN cnt END) AS C男汉1岁学生
,SUM(CAS WHEN sex='M' AND nation='1' AND age='1' AND class1='2' THEN cnt END) AS C男汉1岁工人
,SUM(CAS WHEN sex='M' AND nation='1' AND age='1' AND class1='3' THEN cnt END) AS C男汉1岁农民
,SUM(CAS WHEN sex='M' AND nation='1' AND age='2' AND class1='1' THEN cnt END) AS C男汉2岁学生
,SUM(CAS WHEN sex='M' AND nation='1' AND age='2' AND class1='2' THEN cnt END) AS C男汉2岁工人
,SUM(CAS WHEN sex='M' AND nation='1' AND age='2' AND class1='3' THEN cnt END) AS C男汉2岁农民
,SUM(CAS WHEN sex='M' AND nation='2' AND age='1' AND class1='1' THEN cnt END) AS C男壮1岁学生
,SUM(CAS WHEN sex='M' AND nation='2' AND age='1' AND class1='2' THEN cnt END) AS C男壮1岁工人
,SUM(CAS WHEN sex='M' AND nation='2' AND age='1' AND class1='3' THEN cnt END) AS C男壮1岁农民
,SUM(CAS WHEN sex='M' AND nation='2' AND age='2' AND class1='1' THEN cnt END) AS C男壮2岁学生
,SUM(CAS WHEN sex='M' AND nation='2' AND age='2' AND class1='2' THEN cnt END) AS C男壮2岁工人
,SUM(CAS WHEN sex='M' AND nation='2' AND age='2' AND class1='3' THEN cnt END) AS C男壮2岁农民
FROM T GROUP BY region)
SELECT * FROM t1
上面用了XMLTABLE做解析,用可以用传统的CONNECT BY和SUBSTR解析:
CREATE OR REPLACE FUNCTION fsql1(v_tname varchar2,tr varchar2 ,tc0 varchar2)
RETURN VARCHAR2
IS
lv_sql VARCHAR2(4000);
lv_name VARCHAR2(30);
BEGIN
SELECT cname2
INTO lv_name
FROM eav
WHERE tname = v_tname
AND cname = tr
AND ccode IS NULL;
lv_sql := 'WITH t AS (
SELECT '||tr||','||REPLACE(tc0,' ',',')||',COUNT(*) cnt FROM '||v_tname||' GROUP BY '||tr||','||REPLACE(tc0,' ',',')||')
,t1 AS (
SELECT '||tr||' AS '||lv_name;
FOR lv_rec IN (SELECT SYS_CONNECT_BY_PATH(cname||'='''||ccode||'''',' AND ') AS s1
,'C'||REPLACE(SYS_CONNECT_BY_PATH(cname2,','),',') AS s2
FROM
(SELECT e.*,t.id
FROM eav e
,(SELECT ROWNUM id,SUBSTR(tc0,last_pos,pos-last_pos) AS c
FROM (SELECT LAG(pos,1,0) OVER(ORDER BY pos)+1 last_pos,pos
FROM (SELECT INSTR(tc0,' ',1,ROWNUM) pos FROM DUAL CONNECT BY INSTR(tc0,' ',1,ROWNUM)>0
UNION ALL SELECT LENGTH(tc0)+1 FROM DUAL
)
)
ORDER BY 1
) t
WHERE e.tname = v_tname
AND e.cname = t.c
AND e.ccode IS NOT NULL
) e2
WHERE CONNECT_BY_ISLEAF=1
START WITH id=1
CONNECT BY id = PRIOR id+1
ORDER SIBLINGS BY ccode
)
LOOP
lv_sql := lv_sql ||CHR(10)||' ,SUM(CAS WHEN '||SUBSTR(lv_rec.s1,5)||' THEN cnt END) AS '||lv_rec.s2;
END LOOP;
lv_sql := lv_sql ||CHR(10)||' FROM T GROUP BY '||tr||')
SELECT * FROM t1';
RETURN lv_sql;
END fsql1;
/
[ 本帖最后由 newkid 于 2010-8-13 02:11 编辑 ] |
|