Oracle SQL依然無可替代--《Mastering Oracle SQL》(轉載)
Posted on 2005-12-06 22:04 Terry的Blog 閱讀(873) 評論(0) 編輯 收藏 所屬分類: oracle 、轉載選擇自 calvinxiu 的 Blog http://dev.csdn.net/user/calvinxiu
天寒地凍,呆在家里又讀完了《Mastering Oracle SQL》2nd,發現Oracle的功能還是很強悍,光函數就有兩百個,HSQL是很難比擬的。接下來的硬骨頭,看來要么冒險用Hibernate3.0 的SQL Mapping功能,要么就自己跑JDBC組裝VO了。
1.報表合計專用的Rollup函數
銷售報表
廣州 1月 2000元
廣州 2月 2500元
廣州 4500元
深圳 1月 1000元
深圳 2月 2000元
深圳 3000元
所有地區 7500元
銷售報表
廣州 1月 2000元
廣州 2月 2500元
廣州 4500元
深圳 1月 1000元
深圳 2月 2000元
深圳 3000元
所有地區 7500元
以往的查詢SQL:
Select area,month,sum(money) from SaleOrder group by area,month
然后廣州,深圳的合計和所有地區合計都需要在程序里自行累計
1.其實可以使用如下SQL: Select area,month,sum(total_sale) from SaleOrder group by rollup(area,month)就能產生和報表一模一樣的紀錄
2.如果year不想累加,可以寫成 Select year,month,area,sum(total_sale) from SaleOrder group by year, rollup(month,area) 另外Oracle 9i還支持如下語法: Select year,month,area,sum(total_sale) from SaleOrder group by rollup((year,month),area)
3.如果使用Cube(area,month)而不是RollUp(area,month),除了獲得每個地區的合計之外,還將獲得每個月份的合計,在報表最后顯示。
4.Grouping讓合計列更好讀
RollUp在顯示廣州合計時,月份列為NULL,但更好的做法應該是顯示為"所有月份"
Grouping就是用來判斷當前Column是否是一個合計列,1為yes,然后用Decode把它轉為"所有月份" Select Decode(Grouping(area),1,'所有地區',area) area,
Decode(Grouping(month),1,'所有月份',month),
sum(money)
From SaleOrder
Group by RollUp(area,month);
RollUp在顯示廣州合計時,月份列為NULL,但更好的做法應該是顯示為"所有月份"
Grouping就是用來判斷當前Column是否是一個合計列,1為yes,然后用Decode把它轉為"所有月份" Select Decode(Grouping(area),1,'所有地區',area) area,
Decode(Grouping(month),1,'所有月份',month),
sum(money)
From SaleOrder
Group by RollUp(area,month);
2.對多級層次查詢的start with.....connect by
比如人員組織,產品類別,Oracle提供了很經典的方法
比如人員組織,產品類別,Oracle提供了很經典的方法
SELECT LEVEL, name, emp_id,manager_emp_id
FROM employee
START WITH manager_emp_id is null
CONNECT BY PRIOR emp_id = manager_emp_id;
FROM employee
START WITH manager_emp_id is null
CONNECT BY PRIOR emp_id = manager_emp_id;
上面的語句demo了全部的應用,start with指明從哪里開始遍歷樹,如果從根開始,那么它的manager應該是Null,如果從某個職員開始,可以寫成emp_id='11'
CONNECT BY 就是指明父子關系,注意PRIOR位置
另外還有一個LEVEL列,顯示節點的層次
CONNECT BY 就是指明父子關系,注意PRIOR位置
另外還有一個LEVEL列,顯示節點的層次
3.更多報表/分析決策功能
3.1 分析功能的基本結構
分析功能() over( partion子句,order by子句,窗口子句)
概念上很難講清楚,還是用例子說話比較好.
3.1 分析功能的基本結構
分析功能() over( partion子句,order by子句,窗口子句)
概念上很難講清楚,還是用例子說話比較好.
3.2 Row_Number 和 Rank, DENSE_Rank
用于選出Top 3 sales這樣的報表
當兩個業務員可能有相同業績時,就要使用Rank和Dense_Rank
比如
金額 RowNum Rank Dense_Rank
張三 4000元 1 1 1
李四 3000元 2 2 2
錢五 2000元 3 3 3
孫六 2000元 4 3 3
丁七 1000元 5 5 4
用于選出Top 3 sales這樣的報表
當兩個業務員可能有相同業績時,就要使用Rank和Dense_Rank
比如
金額 RowNum Rank Dense_Rank
張三 4000元 1 1 1
李四 3000元 2 2 2
錢五 2000元 3 3 3
孫六 2000元 4 3 3
丁七 1000元 5 5 4
這時,應該把并列第三的錢五和孫六都選進去,所以用Ranking功能比RowNumber保險.至于Desnse還是Ranking就看具體情況了。
SELECT salesperson_id, SUM(tot_sales) sp_sales,
RANK( ) OVER (ORDER BY SUM(tot_sales) DESC) sales_rank
FROM orders
GROUP BY salesperson_id
RANK( ) OVER (ORDER BY SUM(tot_sales) DESC) sales_rank
FROM orders
GROUP BY salesperson_id
3.3 NTILE 把紀錄平分成甲乙丙丁四等
比如我想取得前25%的紀錄,或者把25%的紀錄當作同一個level平等對待,把另25%當作另一個Level平等對待
比如我想取得前25%的紀錄,或者把25%的紀錄當作同一個level平等對待,把另25%當作另一個Level平等對待
SELECT cust_nbr, SUM(tot_sales) cust_sales,
NTILE(4) OVER (ORDER BY SUM(tot_sales) DESC) sales_quartile
FROM orders
GROUP BY cust_nbr
ORDER BY 3,2 DESC;NTITLE(4)把紀錄以 SUM(tot_sales)排序分成4份.
NTILE(4) OVER (ORDER BY SUM(tot_sales) DESC) sales_quartile
FROM orders
GROUP BY cust_nbr
ORDER BY 3,2 DESC;NTITLE(4)把紀錄以 SUM(tot_sales)排序分成4份.
3.4 輔助分析列和Windows Function
報表除了基本事實數據外,總希望旁邊多些全年總銷量,到目前為止的累計銷量,前后三個月的平均銷量這樣的列來參考.
這種前后三個月的平均和到目前為止的累計銷量就叫windows function, 見下例 SELECT month, SUM(tot_sales) monthly_sales,
SUM(SUM(tot_sales)) OVER (ORDER BY month
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) max_preceeding
FROM orders
GROUP BY month
ORDER BY month;
SELECT month, SUM(tot_sales) monthly_sales,
AVG(SUM(tot_sales)) OVER (ORDER BY month
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) rolling_avg
FROM orders
GROUP BY month
ORDER BY month;
報表除了基本事實數據外,總希望旁邊多些全年總銷量,到目前為止的累計銷量,前后三個月的平均銷量這樣的列來參考.
這種前后三個月的平均和到目前為止的累計銷量就叫windows function, 見下例 SELECT month, SUM(tot_sales) monthly_sales,
SUM(SUM(tot_sales)) OVER (ORDER BY month
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) max_preceeding
FROM orders
GROUP BY month
ORDER BY month;
SELECT month, SUM(tot_sales) monthly_sales,
AVG(SUM(tot_sales)) OVER (ORDER BY month
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) rolling_avg
FROM orders
GROUP BY month
ORDER BY month;
Windows Function的關鍵就是Windows子句的幾個取值
1 PRECEDING 之前的一條記錄
1 FOLLOWING 之后的一條記錄
UNBOUNDED PRECEDING 之前的所有記錄
CURRENT ROW 當前紀錄
1 PRECEDING 之前的一條記錄
1 FOLLOWING 之后的一條記錄
UNBOUNDED PRECEDING 之前的所有記錄
CURRENT ROW 當前紀錄
4.SubQuery總結
SubQuery天天用了,理論上總結一下.SubQuery 分三種
1.Noncorrelated 子查詢 最普通的樣式.
2.Correlated Subqueries 把父查詢的列拉到子查詢里面去,頭一回cyt教我的時候理解了半天.
3.Inline View 也被當成最普通的樣式用了.
SubQuery天天用了,理論上總結一下.SubQuery 分三種
1.Noncorrelated 子查詢 最普通的樣式.
2.Correlated Subqueries 把父查詢的列拉到子查詢里面去,頭一回cyt教我的時候理解了半天.
3.Inline View 也被當成最普通的樣式用了.
然后Noncorrelated 子查詢又有三種情況
1.返回一行一列 where price < (select max(price) from goods )
2.返回多行一列 where price>= ALL (select price from goods where type=2)
or where NOT price< ANY(select price from goods where type=2)
最常用的IN其實就是=ANY()
3.返回多行多列 一次返回多列當然就節省了查詢時間 UPDATE monthly_orders
SET (tot_orders, max_order_amt) =
(SELECT COUNT(*), MAX(sale_price)
FROM cust_order)
DELETE FROM line_item
WHERE (order_nbr, part_nbr) IN
(SELECT order_nbr, part_nbr FROM cust_order c)
1.返回一行一列 where price < (select max(price) from goods )
2.返回多行一列 where price>= ALL (select price from goods where type=2)
or where NOT price< ANY(select price from goods where type=2)
最常用的IN其實就是=ANY()
3.返回多行多列 一次返回多列當然就節省了查詢時間 UPDATE monthly_orders
SET (tot_orders, max_order_amt) =
(SELECT COUNT(*), MAX(sale_price)
FROM cust_order)
DELETE FROM line_item
WHERE (order_nbr, part_nbr) IN
(SELECT order_nbr, part_nbr FROM cust_order c)