1、行列轉換: decode(條件,值1,返回值1,值2,返回值2,...值n,返回值n,預設值); select decode(sign(變數1-變數2),-1,變數1,變數2) from dual; --取較小值 sign()函數根據某個值是0、正數還是負數,分別返回0、1、-1 例如: 變數1 ...
1、行列轉換:
decode(條件,值1,返回值1,值2,返回值2,...值n,返回值n,預設值);
select decode(sign(變數1-變數2),-1,變數1,變數2) from dual; --取較小值
sign()函數根據某個值是0、正數還是負數,分別返回0、1、-1
例如:
變數1=10,變數2=20
則sign(變數1-變數2)返回-1,decode解碼結果為“變數1”,達到了取較小值的目的。
decode(欄位或欄位的運算,值1,值2,值3)
SELECT T.ZRZCODE,
SUM(DECODE(T.LSBZ, 0, 1, 0)) YX,
SUM(DECODE(T.LSBZ, 1, 1, 0)) LS
FROM FW T
GROUP BY T.ZRZCODE;
2、遞歸查詢的優化
lpad/rpad( string, padded_length, [ pad_string ] )
解釋:字元不夠的時候向左或者向右填充。
例如:SQL> select lpad('abcde',10,'x') from dual;
LPAD('ABCDE',10,'X')
xxxxxabcde
- SELECT ID, FATHER_ID, NAME, CONNECT_BY_ISLEAF LEAF
- FROM T_TREE
- START WITH FATHER_ID = 0
- CONNECT BY PRIOR ID = FATHER_ID;
解釋:CONNECT_BY_ISLEAF 判斷該行記錄是否為葉子節點,如果是返回1,否則返回0
START WITH FATHER_ID = 0 規定哪一條記錄為根節點
CONNECT BY PRIOR ID = FATHER_ID 判斷此節點的父節點是哪一條記錄
例子: SELECT LPAD(MENU_NAME, LENGTHB(MENU_NAME) + LEVEL, DECODE(CONNECT_BY_ISLEAF, 1, ' | ', '+')) FROM MENU START WITH PID = '0' CONNECT BY PRIOR ID = PID;
3、利用分析函數排序和去重
http://blog.csdn.net/haiross/article/details/15336313#comments
分析函數是什麼?
分析函數是Oracle專門用於解決複雜報表統計需求的功能強大的函數,它可以在數據中進行分組然後計算基於組的某種統計值,並且每一組的每一行都可以返回一個統計值。
分析函數和聚合函數的不同之處是什麼?
普通的聚合函數用group by分組,每個分組返回一個統計值,返回的欄位名只能是分組名。而分析函數採用partition by分組,並且每組每行都可以返回一個統計值,返回的欄位名可以是每個欄位,因為是對應到記錄的,所以沒有關係。
分析函數的形式
分析函數帶有一個開窗函數over(),包含三個分析子句:分組(partition by), 排序(order by), 視窗(rows) ,他們的使用形式如下:over(partition by xxx order by yyy rows between zzz)
開窗函數over()包含三個分析子句:分組子句(partition by), 排序子句(order by), 視窗子句(rows)
視窗就是分析函數分析時要處理的數據範圍,就拿sum來說,它是sum視窗中的記錄而不是整個分組中的記錄,因此我們在想得到某個欄位的累計值時,我們需要把視窗指定到該分組中的第一行數據到當前行, 如果你指定該視窗從該分組中的第一行到最後一行,那麼該組中的每一個sum值都會一樣,即整個組的總和。
OVER(PARTITION BY DEPTNO ORDER BY ENAME ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW):當前組第一行到當前行的彙總
OVER(PARTITION BY DEPTNO ORDER BY ENAME ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING):當前行到最後一行的彙總
OVER(PARTITION BY DEPTNO ORDER BY ENAME ROWS BETWEEN 1 PRECEDING AND CURRENT ROW):當前行的上一行(rownum-1)到當前行的彙總
OVER(PARTITION BY DEPTNO ORDER BY ENAME ROWS BETWEEN 1 PRECEDING AND 2 FOLLOWING):當前行的上一行(rownum-1)到下兩行(rownum+2)的彙總
而無論是否省略分組子句,如下結論都是成立的:
1、視窗子句不能單獨出現,必須有order by子句時才能出現。
2、當省略視窗子句時:
a) 如果存在order by則預設的視窗是unbounded preceding and current row --當前組的第一行到當前行,即在當前組中,第一行到當前行
b) 如果同時省略order by則預設的視窗是unbounded preceding and unbounded following --整個組
兩個order by的執行時機
分析函數(以及與其配合的開窗函數over())是在整個sql查詢結束後(sql語句中的order by的執行比較特殊)再進行的操作, 也就是說sql語句中的order by也會影響分析函數的執行結果:
a) 兩者一致:如果sql語句中的order by滿足與分析函數配合的開窗函數over()分析時要求的排序,即sql語句中的order by子句里的內容和開窗函數over()中的order by子句里的內容一樣,那麼sql語句中的排序將先執行,分析函數在分析時就不必再排序;
b) 兩者不一致:如果sql語句中的order by不滿足與分析函數配合的開窗函數over()分析時要求的排序,即sql語句中的order by子句里的內容和開窗函數over()中的order by子句里的內容不一樣,那麼sql語句中的排序將最後在分析函數分析結束後執行排序。
常用的分析函數:
1、row_number() over(partition by ... order by ...) 為每一條記錄返回一個唯一的值。當碰到相同數據時,排名按照記錄集中記錄的順序依次遞增,現實情景為:個人在分組內的排名
2、rank() over(partition by ... order by ...) 得到每條記錄在數據中的排名,排名不跳躍
3、dense_rank() over(partition by ... order by ...) 得到每條記錄在數據中的排名,排名跳躍
4、count() over(partition by ... order by ...) 每個分組中,某個欄位的統計
5、max() over(partition by ... order by ...)
6、min() over(partition by ... order by ...)
7、sum() over(partition by ... order by ...)
8、avg() over(partition by ... order by ...)
9、first_value() over(partition by ... order by ...) 得到第一個記錄值
10、last_value() over(partition by ... order by ...) 得到最後一個記錄值
11、lag() over(partition by ... order by ...) lag函數可以在一次查詢中取出同一欄位的前n行的數據
12、lead() over(partition by ... order by ...) lead函數可以在一次查詢中取出同一欄位的後n行的值
lag(arg1,arg2,arg3)
第一個參數是列名,
第二個參數是偏移的offset,
第三個參數是超出記錄視窗時的預設值。
select id,name,lag(name,1,0) over(order by id) from kkk;
去重:
1、利用rowid的唯一性查詢或刪除重覆數據
SELECT * FROM T_FWXX a WHERE a.ROWID <> (SELECT MIN(b.ROWID) FROM T_FWXX b WHERE a. FWZL =b. FWZL);
select ROWNUM,ROWID,d1.* from dept2 d1 where d1.rowid=(select min(d2.rowid) from dept2 d2 where d2.deptno=d1.deptno);
2、給定重覆行序號並去重
SELECT FWZL FROM (SELECT FWZL, ROW_NUMBER() OVER(PARTITION BY FWZL ORDER BY ID DESC) RN FROM T_FWXX) F WHERE F.RN = 1 聚合函數(within group語法): SELECT RANK(50000234, 38) WITHIN GROUP(ORDER BY ZRZ.ZRZCODE, FW.ZZMJ DESC) PM FROM FW, ZRZ WHERE FW.ZRZCODE = ZRZ.ZRZCODE AND ZRZ.ZRZCODE = 50000234;--給定面積在幢中排名RANK(50000234,38)即:當zrz.zrzcode=50000234和fw.zzmj=38,插入到資料庫後的排名是多少?
如果存在一條記錄,這條記錄的salary欄位值為1500。
那麼將該條記錄插入employees表中後,按照salary欄位降序排列後,該條記錄的序號為多少?
可以使用within group關鍵字的函數有rank,dense_rank,PERCENT_RANK,PERCENTILE_CONT,PERCENTILE_DISC等
4、求占比、小計和總計
分析函數RATIO_TO_REPORT 用來計算當前記錄的指標expr占開窗函數over中包含記錄的所有同一指標的百分比. 這裡如果開窗函數的統計結果為null或者為0,就是說占用比率的被除數為0或者為null, 則得到的結果也為0. 開窗條件query_partition_clause決定被除數的值, 如果用戶忽略了這個條件, 則計算查詢結果中所有記錄的彙總值. 用戶不能使用其他分析函數或者ratio_to_report作為分析函數ratio_to_report的參數expr, 也就是說這個函數
SELECT ZRZ.ZRZCODE, ZRZ.ZH, FW.FWZL, FW.ZZMJ, ROUND(RATIO_TO_REPORT(FW.ZZMJ) OVER(PARTITION BY ZRZ.ZRZCODE) * 100,3) SCALE FROM FW, ZRZ WHERE FW.ZRZCODE = ZRZ.ZRZCODE AND ZRZ.ZRZCODE = 50000234;--房屋面積占幢中面積比例 select deptno,ename,empno,round(RATIO_TO_REPORT(sal) OVER(PARTITION BY deptno)*100,1) 百分比 from emp2rollup()與cube():排列組合分組
1)、group by rollup(a, b, c):
首先會對(a、b、c)進行group by,
然後再對(a、b)進行group by,
其後再對(a)進行group by,
最後對全表進行彙總操作。
2)、group by cube(a, b, c):
則首先會對(a、b、c)進行group by,
然後依次是(a、b),(a、c),(a),(b、c),(b),(c),
最後對全表進行彙總操作。
ROLLUP,是GROUP BY子句的一種擴展,可以為每個分組返回小計記錄以及為所有分組返回總計記錄。
CUBE,也是GROUP BY子句的一種擴展,可以返回每一個列組合的小計記錄,同時在末尾加上總計記錄。
select deptno,sum(sal) from emp2 group by rollup(deptno) SELECT E.LOCALE, E.GENDER, COUNT(1) FROM EMPLOYEE E GROUP BY ROLLUP(E.LOCALE, E.GENDER) ORDER BY E.LOCALE, E.GENDER;--小計,總計 SELECT E.LOCALE, E.GENDER, COUNT(1) FROM EMPLOYEE E GROUP BY CUBE(E.LOCALE, E.GENDER) ORDER BY E.LOCALE, E.GENDER;--X,Y軸同時求小計
5、單條記錄插入多表
原理:利用一個insert all 語法:insert all when .. then
INSERT ALL WHEN LOCALE = 1 THEN INTO EMPLOYEE1(ID, LOCALE, NAME, AGE, GENDER, CODE) VALUES (ID, LOCALE, NAME, AGE, GENDER, CODE) WHEN LOCALE = 32 THEN INTO EMPLOYEE2(ID, LOCALE, NAME, AGE, GENDER, CODE) VALUES(ID, LOCALE, NAME, AGE, GENDER, CODE) insert all into table values() into table values()
6、Merge的使用
解釋:DML語句,適用於批量處理
MERGE INTO table_name alias1
USING (table|view|sub_query) alias2
ON (join condition)
WHEN MATCHED THEN
UPDATE table_name
SET col1 = col_val1,
col2 = col2_val where 條件
WHEN NOT MATCHED THEN
INSERT (column_list) VALUES (column_values) where 條件;
MERGE INTO EMPLOYEE E
USING (SELECT * FROM EMPLOYEE1) E1 ON (E.NAME = E1.NAME) WHEN MATCHED THEN UPDATE SET E.CODE = E1.CODE, E.AGE = E1.AGE WHEN NOT MATCHED THEN INSERT (E.ID, E.LOCALE, E.NAME, E.AGE, E.GENDER, E.CODE) VALUES(E1.ID, E1.LOCALE, E1.NAME, E1.AGE, E1.GENDER, E1.CODE);
7、KEEP的使用
keep是Oracle下的另一個分析函數,他的用法不同於通過over關鍵字指定的分析函數,可以用於這樣一種場合下:取同一個分組下以某個欄位排序後,對指定欄位取最小或最大的那個值。
一般寫法是 MIN [ MAX ] (A) KEEP(DENSE_RANK FIRST [ LAST ] ORDER BY B),這裡引用別人說的明的解釋一下:
DENSE_RANK
功能描述:根據ORDER BY子句中表達式的值,從查詢返回的每一行,計算它們與其它行的相對位置。組內的數據按ORDER BY子句排序,然後給每一行賦一個號,從而形成一個序列,該序列從1開始,往後累加。每次ORDER BY表達式的值發生變化時,該序列也隨之增加。有同樣值的行得到同樣的數字序號(認為null時相等的)。密集的序列返回的時沒有間隔的數。
FIRST
功能描述:從DENSE_RANK返回的集合中取出排在最前面的一個值的行(可能多行,因為值可能相等),因此完整的語法需要在開始處加上一個集合函數以從中取出記錄。
LAST 功能描述:從DENSE_RANK返回的集合中取出排在最後面的一個值的行(可能多行,因為值可能相等),因此完整的語法需要在開始處加上一個集合函數以從中取出記錄。所以預設排序下,FIRST可以理解是取小值,LAST取大值。而前面的MIN或者MAX則是在KEEP的結果集中取某一欄位的最大值或最小值。
keep和普通分析函數的區別:普通的分析函數只是列出分組後的記錄,而對每一個組的記錄進行統計分析。
keep對分組內的函數通過order by和max(),min()選取某個欄位的值。可以理解成這裡的keep就是sum() groud by deptno 前的sum()那樣
實例:取出各個部門薪資最高的員工編號
1、select deptno,empno,sal,max(empno) keep(dense_rank first order by sal desc) over(partition by deptno) from emp2
2、select deptno,max(empno) keep(dense_rank first order by sal desc) from emp2 group by deptno
8、SQL查詢正則表達式的使用
ORACLE中的支持正則表達式的函數主要有下麵四個:
1,REGEXP_LIKE :與LIKE的功能相似
select * from emp2 where regexp_like(empno,'7[0-9]{2}9')
2,REGEXP_INSTR :與INSTR的功能相似
REGEXP_INSTR
6個參數
第一個是輸入的字元串
第二個是正則表達式
第三個是標識從第幾個字元開始正則表達式匹配。(預設為1)
第四個是標識第幾個匹配組。(預設為1)
第五個是指定返回值的類型,如果該參數為0,則返回值為匹配位置的第一個字元,如果該值為非0則返回匹配值的最後一個位置。
第六個是是取值範圍:
i:大小寫不敏感;
c:大小寫敏感;
n:點號 . 不匹配換行符號;
m:多行模式;
x:擴展模式,忽略正則表達式中的空白字元。
SELECT REGEXP_INSTR(a,'[0-9]+') AS A FROM test_reg_substr;
3,REGEXP_SUBSTR :與SUBSTR的功能相似
REGEXP_SUBSTR函數格式如下:
function REGEXP_SUBSTR(String, pattern, position, occurrence, modifier)
__srcstr :需要進行正則處理的字元串
__pattern :進行匹配的正則表達式
__position :起始位置,從第幾個字元開始正則表達式匹配(預設為1)
__occurrence :標識第幾個匹配組,預設為1
__modifier :模式('i'不區分大小寫進行檢索;'c'區分大小寫進行檢索。預設為'c'。)
- --1、查詢使用正則分割後的第一個值,也就是34
- SELECT REGEXP_SUBSTR('34,56,-23','[^,]+',1,1,'i') AS STR FROM DUAL;
- --結果是:34
- --2、查詢使用正則分割後的最後一個值,也就是-23
- SELECT REGEXP_SUBSTR('34,56,-23','[^,]+',1,3,'i') AS STR FROM DUAL;
- --結果是:-23
4,REGEXP_REPLACE :與REPLACE的功能相似
9、常見函數
TRUNC:截取函數 EXTRACT:用於從一個date或者interval類型中截取到特定的部分 NVL DECODElength:字元長度
lengthb:位元組長度
ASCII INITCAP:首字母大寫 SOUNDEX:返回由四個字元組成的代碼 (SOUNDEX) 以評估兩個字元串的相似性 MONTHS_BETWEEN ADD_MONTHS NEXT_DAY LAST_DAY ROUND:函數用於把數值欄位舍入為指定的小數位數
10、分頁函數
--普通寫法
SELECT AA.FWZL, AA.FWTYBH
FROM (SELECT A.FWZL, A.FWTYBH, ROWNUM RN
FROM (SELECT F.FWZL, F.FWTYBH FROM FW F ORDER BY F.FWTYBH DESC) A
WHERE ROWNUM <= 120020) AA
WHERE AA.RN > 120000;
--rowid寫法 SELECT /*+ ROWID(FW) */ FW.FWZL, FW.FWTYBH
FROM FW FW,
(SELECT AA.RID, AA.RN
FROM (SELECT A.RID, ROWNUM RN
FROM (SELECT /*+ index(F IDX_FW_FWTYBH) */
ROWID RID
FROM FW F
ORDER BY F.FWTYBH DESC) A
WHERE ROWNUM <= 120020) AA
WHERE AA.RN > 120000) B
WHERE FW.ROWID = B.RID;