城市1 城市2 城市3 城市4
2010-06 0 1 0 0
2010-08 0 1 0 2
2010-07 0 0 1 0
2010-05 1 0 0 0
時間和記錄都是從sino_user查詢出來的,而列名是從sino_ip表中查詢出來。本來用列舉法,直接把所有城市都用case when進行判斷一遍就ok,但是,sino_ip表中城市個數是不定的,就是說今天查詢出來時4個城市,明天也許就是5個城市。這就需要我們的統計能支援列的動態新增。我第一想到的是試圖(view),但是這個試圖怎麼寫,才能保證動態生成列呢,這就要使用動態sql,而動態sql在**生成能,嘿嘿,說了半天總算到正題了,沒錯,就是儲存過程。可以使用儲存過程動態生成view,然後根據view來查詢。
1、資料基礎
表結構我就不寫了,和上篇博文一樣的。
2、問題分析
select s.dd
,sum(city1) 城市1
,sum(city2) 城市2
,sum(city3) 城市3
,sum(city4) 城市4
,sum(city5) 城市5
from (select substr(to_char(t.update_time,'yyyy-mm-dd'),1,7) dd
,case when t1.city ='城市1' then 1 else 0 end city1
,case when t1.city ='城市2' then 1 else 0 end city2
,case when t1.city ='城市3' then 1 else 0 end city3
,case when t1.city ='城市4' then 1 else 0 end city4
,case when t1.city ='城市5' then 1 else 0 end city5
from sino_user t , sino_ip t1
where f_ip2number(t.ip) between f_ip2number(t1.ip_begin) and f_ip2number(t1.ip_end)) s group by s.dd
我們可以發現,sum部分和case when 部分都可以通過迴圈來新增,因此,我們可以把從城市對應ip段表中查詢出來的資料存放在游標中,通過迴圈來生成統計sql。
let's do it。
3、編寫過程
create or replace procedure p_count is
v_sql dbms_sql.varchar2s;
l_cursor integer default dbms_sql.open_cursor;
l_rows number default 0;
i number default 2;
begin
v_sql(1) := 'create or replace view v_count as select s.dd';
for c_col in (select id,city from sino_ip order by id) loop
v_sql(i) := ',sum(city' ||c_col.id||') '||c_col.city;
i := i+1;
end loop;
v_sql(i) := 'from (select substr(to_char(t.update_time,''yyyy-mm-dd''),1,7) dd';
for c_col2 in (select id,city from sino_ip order by id) loop
v_sql(i+1) := ',case when t1.city ='''||c_col2.city||''' then 1 else 0 end city'|| c_col2.id;
i:= i + 1;
end loop;
v_sql(i+1) := 'from sino_user t , sino_ip t1 ';
v_sql(i+2) := 'where f_ip2number(t.ip) between f_ip2number(t1.ip_begin) and f_ip2number(t1.ip_end)) s group by s.dd';
dbms_sql.parse(c => l_cursor,statement => v_sql,lb => v_sql.first,ub => v_sql.last,lf*** => true,language_flag => dbms_sql.native );
l_rows := dbms_sql.execute(l_cursor);
dbms_sql.close_cursor( l_cursor );
dbms_output.put_line(l_rows);
exception
when others then
dbms_output.put_line(sqlerrm);
end p_count;
注:過程中用到的f_ip2number函式可以到另乙個博文「如何使用sql查詢ip位址所屬ip段 」裡面去看,我就不再贅述。
大家可能注意到,我的在儲存過程中用來存放動態sql不是用varchar2,用的是dbms_sql.varchar2s,這是因為varchar2只能存放32k的字元,而我們的sql是很長,將來會更長,因此使用dbms_sql.varchar2分行來儲存sql。
同時,sql的執行也不能使用execute immediate,因為它也只能執行32k的sql,我們使用dmbs_sql.parse,通過游標來執行。
ok,執行。
報錯了.....
沒有足夠的許可權。
呵呵,我們在pl/sql中建立檢視需要建立檢視的許可權。
ok,我們給賬號個create any view的許可權。
執行沒報錯。
我們來查詢view
select * from v_count t
結果出來了,和我上面寫的要求一樣。
那我們來驗證它能不能動態生成列。
我們在sino_ip插入城市5,乙個新的ip段,然後在sino_user表中插入一條ip資料城市5的記錄。再來查詢:
城市1 城市2 城市3 城市4 城市5
2010-06 0 1 0 0 0
2010-08 0 1 0 2 0
2010-07 0 0 1 0 0
2010-05 1 0 0 0 1
ok,成功了。哈哈
虧了今天胡老大到我們那視察,不用上班,我才有空把最近做的東西記下來。
MySQL將查詢結果插入到另乙個表中
1 如果兩張表 查詢表和插入表 的字段一致,並且希望插入查詢表的全部資料,可以用此方法 insert into 目標表 select from 表 insert into user login1 select from user login 2 如果只希望插入指定字段,可以用此方法,注意兩表的字段型...
Hive實驗 將 查詢結果儲存到另乙個表中
查詢employee表,按部門分組,女性個數降序排序,將結果employee res表中 欄位為 部門id,女性個數 建表 建立表 employee hive create external table employee sid string,jdata string,name string,cit...
將乙個表的結果集插入到另乙個表中
舉例1 insert into table b time,score,totalscore select time,score,sum score over order bytime from table a 舉例2 insert into jobinfo analysis salary,addre...