SQL進階(上)
阿新 • • 發佈:2018-12-13
CASE表示式
新手用WHERE字句進行條件分支,高手用SELECT字句進行條件分支
--男性人口
SELECT pref_name,
SUM(population)
FROM PopTbl2
WHERE sex='1'
GROUP BY pref_name
--女性人口
SELECT pref_name
SUM(population)
FROM PopTbl2
WHERE sex='2'
GROUP BY pref_name
SELECT pref_name, --男性人口 SUM(CASE WHEN sex='1' THEN population ELSE 0 END) AS cnt_m, --女性人口 SUM(CASE WHEN sex='2' THEN population ELSE 0 END)AS cnt_f, FROM PopTbl2 GROUP BY pref_name;
新手用HAVING子句進行條件分支,高手用SELECT子句進行條件分支
--選擇只加入一個社團的學生
SELECT std_id,MAX(club_id)AS main_club
FROM StudentClub
GROUP BY std_id
HAVING COUNT(*)=1;
--選擇加入了多個社團的學生
SELECT std_id,club_id AS main_club
FROM StudentClub
WHERE main_club_flg='Y';
SELECT std_id, CASE WHERE COUNT(*)=1 --只加入一個社團的學生 THEN MAX(club_id) ELSE MAX(CASE WHEN main_club_flag='Y' THEN club_id ELSE NULL END) END AS main_club FROM StudentClub GROUP BY std_id
自連線的用法
刪除重複行
DELETE FROM Products P1
WHERE EXISTS(SELECT *
FROM Products P2
WHERE P1.name =P2.name
AND P1.price=P2.price
AND P1.rowid <P2.rowid);
查詢區域性不一致的列
--用於查詢價格相等但商品名稱不同的記錄的SQL語句 SELECT DISTINCT P1。name,P1.price FROM Products P1,Products P2 WHERE P1.price =p2.price AND P1.name<>P2.name
排序
--排序,使用視窗函式
SELECT name,price
RANK() OVER (ORDER BY price DESC) AS rank_1,
DENSE_RANK() OVER(ORDER BY price DESC)AS rank_2
FROM Products
三值邏輯和NULL
true和false兩個值,第三個值unknown
- 排中律不成立
- NOT IN和NOT EXISTS不是等價的
HAVING子句的力量
尋找缺失的編號
--如果有查詢結果,說明存在缺失的編號
SELECT '存在缺失的編號' AS gap
FROM SeqTbl
HAVING COUNT(*)<>MAX(seq)
求眾數
SELECT income,COUNT(*)AS cnt
FROM Graduates
GROUP BY income
HAVING COUNT(*) >=ALL(SELECT COUNT(*)
FROM Graduates
GROUP BY income)
求中位數
--求中位數SQL語句:在HAVING子句中使用非等值自連線
SELECT AVG(DISTINCT income)
FROM (SELECT T1.income
FROM Graduates T1,Graduates T2
GROUP BY T1.income)
--S1的條件
HAVING SUM(CASE WHEN T2.income >=T1.income THEN 1 ELSE 0 END)>=COUNT(*)/2
AND SUM(CASE WHERE T2.income<=T1.income THEN 1 ELSE 0 END)>=COUNT(*)/2) TEP
查詢不包含NULL的集合
--在對包含NULL的列使用時,COUNT(*)和COUNT(列名)的查詢結果是不同的
SELECT COUNT(*),COUNT(col_1)
FROM NUllTbl
外連線的用法
用外連線進行行列轉換(行→列)
--水平展開求交叉表
SELECT C0,name,
CASE WHEN C1.name IS NOT NULL THEN 'O' ELSE NULL END AS "SQL入門"
CASE WHEN C2.name IS NOT NULL THEN 'O' ELSE NULL END AS "UNIX基礎"
CASE WHEN C3.name IS NOT NULL THEN 'O' ELSE NULL END AS "Java中級"
FROM (SELECT DISTINCT name FROM Courses)CO --這裡的Co是側欄
LEFT OUTER JOIN
(SELECT name FROM Courses WHERE course ='SQL入門')C1 ON CO.name =C1.name
LEFT OUTER JOIN
(SELECT name FROM Courses WHERE course='UNIX基礎')C2 ON C0.name=C2.name
LEFT OUTEER JOIN
(SELECT name FROM Courses WHERE course='Java中級')C3 ON C0.name=C3.name
用外連線進行行列轉換(列→行)
--列資料轉換成行資料;使用UNION ALL
SELECT employee,child_1 AS child FROM Personnel UNION ALL
SELECT employee,child_2 AS child FROM Personnel UNION ALL
SELECT employee,child_3 AS child FROM Personnel
用外連線求差集:A-B
SELECT A.id AS id,A.name AS A_name
FROM Class_A A LEFT OUTER JOIN CLass_B B
ON A.id =B.id
WHERE B.name IS NULL
用全外連線求異或集
SELECT COALESCE(A.id,B.id)AS id,
COALESCE(A.name,B.name)AS name
FROM Class_A A FULL OUTER OUTER JOIN Class_B B
ON A.id=B.id
WHERE A.name IS NULL
OR B.name IS NULL
用關聯子查詢比較行與行
和上一年比較結果
--求出的是增長了還是減少了,亦或者是維持現狀,使用關聯子查詢
SELECT S1.year,S1.sale,
CASE WHEN sale=
(SELECT sale
FROM Sales S2
WHERE S2.year =S1.year-1)THEN '→'--持平
WHEN sale>
(SELECT sale
FROM Sales S2
WHERE S2.year =S1.year-1)THEN '↑'--增長
WHEN sale<
(SELECT sale
FROM Sales S2
WHERE S2.year =S1.year-1)THEN '↓'--減少
ELSE '-' END AS var
FROM Sales S1
ORDER BY year;
和過去最臨近的年份營業額相同的年份,同時使用自連線
SELECT S1.year AS year,
S1.year AS year,
FROM Sale2 S1,Sales2 S2
WHERE S1.sale =S2.sale
AND S2.year =(SELECT MAX(year)
FROM Sales2 S3
WHERE S1.year>S3.year)
ORDER BY year;
移動累計值
--求累計值;使用肥羅已滿型遞迴集合
SELECT prc_data, A1.prc_amt,
(SELECT SUM(prc_amt)
FROM Accounts A2
WHERE A1.prc_date >=A2.prc_date)AS onhand_amt
FROM Accounts A1
ORDER BY prc_date;
查詢重疊的時間區間
--求重疊的住宿期間
SELECT reserver,start_date,end_date
FROM Reservations R1
WHERE EXISTS
(SELECT *
FROM Reservations R2
WHERE R1.reserver<> R2.reserver --與自己以外的客人進行比較
AND (R1.start_date BETWEEN R2.start_date AND R2.end_date
--自己的入住日期在他人的住宿期間
OR R1.end_date BETWEEN R2.start_date AND R2.end_date));
--自己的離店日期在他人的住宿期間內