【數據庫系列】|CASE表達式

1.case表達式寫法

-- 簡單 CASE 表達式
CASE sex
WHEN '1' THEN '男'
WHEN '2' THEN '女'
ELSE '其他' END 
-- 搜索 CASE 表達式
CASE WHEN sex = '1' THEN '男'
WHEN sex = '2' THEN '女'
ELSE '其他' END

2.注意事項

2.1 統一各分支返回的數據類型

CASE 表達式里各個分支返回的數據類型是否一致。某個分支返回字符型,而其他
分支返回數值型的寫法是不正確的。

2.2 注意 不要忘了寫END

2.3養成寫else的習慣

與 END 不同, ELSE 子句是可選的,不寫也不會出錯。不寫 ELSE 子句時,CASE 表達式的執行結果是 NULL。但是不寫可能會造成“語法沒有錯誤,結 果卻不對”這種不易追查原因的麻煩,所以最好明確地寫上 ELSE 子句(即便是在結果可以為 NULL 的情況下)。養成這樣的習慣后,我們從代碼上就可以清楚地看到這種條件下會生成 NULL,而且將來代碼有修改時也能減少失誤。

3.例子

3.1 例子1
/* 將已有編號方式轉換為新的方式并統計 */
CREATE TABLE PopTbl
(pref_name VARCHAR(32) PRIMARY KEY,
 population INTEGER NOT NULL);

INSERT INTO PopTbl VALUES('杭州', 100);
INSERT INTO PopTbl VALUES('湖州', 200);
INSERT INTO PopTbl VALUES('金華', 150);
INSERT INTO PopTbl VALUES('衢州', 200);
INSERT INTO PopTbl VALUES('寧波', 300);
INSERT INTO PopTbl VALUES('深圳', 100);
INSERT INTO PopTbl VALUES('廣州', 200);
INSERT INTO PopTbl VALUES('東莞', 400);
INSERT INTO PopTbl VALUES('長沙', 50);
/*在group by 后面加select后的別名是違反標準 SQL 的規則的,
因為 GROUP BY 子句比 SELECT 語句先執行,所以在 GROUP BY 子句中引
用在 SELECT 子句里定義的別稱是不被允許的。事實上,在 Oracle、 DB2、
SQL Server 等數據庫里采用這種寫法時就會出錯。
不過也有支持這種 SQL 語句的數據庫,例如在 PostgreSQL 和 MySQL
中,這個查詢語句就可以順利執行。這是因為,這些數據庫在執行查詢語
句時,會先對 SELECT 子句里的列表進行掃描,并對列進行計算。*/
SELECT (case when city in('杭州','湖州','金華','衢州','寧波') then '浙江'
                        when city in('深圳','廣州','東莞') then '廣東'
                        else '湖南' end) 地區名,sum(population) as 人口
from poptbl
group by 地區名

3.2例子2 交叉表

/* 將“行結構”的數據轉換成了“列結構”的數據。除了 SUM, COUNT、 AVG 等聚合函數也都可以用于將行結構的數據轉換成列結構的數據。 */
CREATE TABLE PopTbl2
(city VARCHAR(32),
 sex CHAR(1) NOT NULL,
 population INTEGER NOT NULL,
    PRIMARY KEY(city, sex));

INSERT INTO PopTbl2 VALUES('杭州', '1',   60 );
INSERT INTO PopTbl2 VALUES('杭州', '2',   40 );
INSERT INTO PopTbl2 VALUES('湖州', '1',   100);
INSERT INTO PopTbl2 VALUES('湖州', '2',   100);
INSERT INTO PopTbl2 VALUES('金華', '1',   100);
INSERT INTO PopTbl2 VALUES('金華', '2',   50 );
INSERT INTO PopTbl2 VALUES('衢州', '1',   100);
INSERT INTO PopTbl2 VALUES('衢州', '2',   100);
INSERT INTO PopTbl2 VALUES('寧波', '1',   100);
INSERT INTO PopTbl2 VALUES('寧波', '2',   200);
INSERT INTO PopTbl2 VALUES('深圳', '1',   20 );
INSERT INTO PopTbl2 VALUES('深圳', '2',   80 );
INSERT INTO PopTbl2 VALUES('廣州', '1',   125);
INSERT INTO PopTbl2 VALUES('廣州', '2',   125);
INSERT INTO PopTbl2 VALUES('東莞', '1',   250);
INSERT INTO PopTbl2 VALUES('東莞', '2',   150);
INSERT INTO PopTbl2 VALUES('長沙', '1',   250);
INSERT INTO PopTbl2 VALUES('長沙', '2',   150);


select city,sum(case when sex='1' then population else 0 end) '男',
sum(case when sex='2' then population else 0 end) '女'
from poptbl2
group by city;

select case when sex=1 then '男' else '女' end as sex,
sum(population) '全國',
                sum(case when city in ('杭州','金華','湖州','寧波','衢州') then population else 0 end) '浙江',
                sum(case when city in ('深圳','東莞','廣州') then population else 0 end) '廣東',
                sum(case when city ='長沙' then population else 0 end)'湖南'
from poptbl2
group by sex

/*在 CASE 表達式里,我們可以使用 BETWEEN、 LIKE 和 <、 > 等
便利的謂詞組合,以及能嵌套子查詢的 IN 和 EXISTS 謂詞。*/

/* 表之間的數據匹配 */
CREATE TABLE CourseMaster
(course_id   INTEGER PRIMARY KEY,
 course_name VARCHAR(32) NOT NULL);

INSERT INTO CourseMaster VALUES(1, '會計入門');
INSERT INTO CourseMaster VALUES(2, '財務知識');
INSERT INTO CourseMaster VALUES(3, '簿記考試');
INSERT INTO CourseMaster VALUES(4, '稅務師');

CREATE TABLE OpenCourses
(month       INTEGER ,
 course_id   INTEGER ,
    PRIMARY KEY(month, course_id));

INSERT INTO OpenCourses VALUES(200706, 1);
INSERT INTO OpenCourses VALUES(200706, 3);
INSERT INTO OpenCourses VALUES(200706, 4);
INSERT INTO OpenCourses VALUES(200707, 4);
INSERT INTO OpenCourses VALUES(200708, 2);
INSERT INTO OpenCourses VALUES(200708, 4);

-- 表的匹配:使用inner join
select a.course_name,
            sum(case when b.month=200706 then 1 else 0 end) '6月',
            sum(case when b.month=200707 then 1 else 0 end) '7月',
            sum(case when b.month=200708 then 1 else 0 end) '8月'
from coursemaster a
inner join opencourses b
on a.course_id=b.course_id
group by a.course_name

/*無論使用 IN 還是 EXISTS,得到的結果是一樣的,但從性能方面來說,
EXISTS 更好。通過 EXISTS 進行的子查詢能夠用到“month, course_
id”這樣的主鍵索引,因此尤其是當表 OpenCourses 里數據比較多的時候
更有優勢*/

-- 表的匹配 :使用 IN 謂詞
SELECT course_name,
CASE WHEN course_id IN
(SELECT course_id FROM OpenCourses
WHERE month = 200706) THEN '○'
ELSE '×' END AS "6 月",
CASE WHEN course_id IN
(SELECT course_id FROM OpenCourses
WHERE month = 200707) THEN '○'
ELSE '×' END AS "7 月",
CASE WHEN course_id IN
(SELECT course_id FROM OpenCourses
WHERE month = 200708) THEN '○'
ELSE '×' END AS "8 月"
FROM CourseMaster;

-- 表的匹配 :使用 EXISTS 謂詞
SELECT CM.course_name,
CASE WHEN EXISTS
(SELECT course_id FROM OpenCourses OC
WHERE month = 200706 
AND OC.course_id = CM.course_id) THEN '○'
ELSE '×' END AS "6 月",
CASE WHEN EXISTS
(SELECT course_id FROM OpenCourses OC
WHERE month = 200707
AND OC.course_id = CM.course_id) THEN '○'
ELSE '×' END AS "7 月",
CASE WHEN EXISTS
(SELECT course_id FROM OpenCourses OC
WHERE month = 200708
AND OC.course_id = CM.course_id) THEN '○'
ELSE '×' END AS "8 月"
FROM CourseMaster CM;

例3:在case中使用聚合函數

/* 在CASE表達式中使用聚合函數 */
CREATE TABLE StudentClub
(std_id  INTEGER,
 club_id INTEGER,
 club_name VARCHAR(32),
 main_club_flg CHAR(1),
 PRIMARY KEY (std_id, club_id));

INSERT INTO StudentClub VALUES(100, 1, '棒球',        'Y');
INSERT INTO StudentClub VALUES(100, 2, '管弦樂',      'N');
INSERT INTO StudentClub VALUES(200, 2, '管弦樂',      'N');
INSERT INTO StudentClub VALUES(200, 3, '羽毛球','Y');
INSERT INTO StudentClub VALUES(200, 4, '足球',    'N');
INSERT INTO StudentClub VALUES(300, 4, '足球',    'N');
INSERT INTO StudentClub VALUES(400, 5, '游泳',        'N');
INSERT INTO StudentClub VALUES(500, 6, '圍棋',        'N');


--1. 獲取只加入了一個社團的學生的社團 ID。
select std_id,club_name,club_id
from studentclub
group by std_id
having count(std_id)=1

--2. 獲取加入了多個社團的學生的主社團 ID。
select a.std_id,a.club_id
from
(select std_id,club_name,club_id,main_club_flg
from studentclub
order by std_id,main_club_flg desc) a
group by a.std_id
having count(a.std_id)>1


--同時獲取以上的兩條要求
SELECT std_id,
            CASE WHEN COUNT(*) = 1 -- 只加入了一個社團的學生
            THEN MAX(club_id)
            ELSE MAX(CASE WHEN main_club_flg = 'Y'
                                THEN club_id
                            ELSE NULL END)
            END AS main_club,
            case when count(*) = 1
            then '只加入了一個社區'
            else '加入了多個社團' end as '參加幾個社團'
FROM StudentClub
GROUP BY std_id

4.練習題

/* 練習題1-1:多列數據的最大值(練習題1-1-3也會用到) */
CREATE TABLE Greatests(keyy CHAR(1) PRIMARY KEY,
 x   INTEGER NOT NULL,
 y   INTEGER NOT NULL,
 z   INTEGER NOT NULL);

INSERT INTO Greatests VALUES('A', 1, 2, 3);
INSERT INTO Greatests VALUES('B', 5, 5, 2);
INSERT INTO Greatests VALUES('C', 4, 7, 1);
INSERT INTO Greatests VALUES('D', 3, 3, 8);

#練習1-1-1,找到x,y,z三列中的最大值
##思路一,將列轉化為行
select a.keyy,max(a.ok)
from
(select keyy,x ok
from greatests
union all
select keyy,y ok
from greatests
union all
select keyy,z ok
from greatests) a
group by a.keyy
##思路二,直接用case
/* 求x、y和z中的最大值 */
SELECT key,
       CASE WHEN CASE WHEN x < y THEN y ELSE x END < z
            THEN z
            ELSE CASE WHEN x < y THEN y ELSE x END
        END AS greatest
  FROM Greatests;

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執行單位為行(line),也就是一...
    悟名先生閱讀 4,195評論 0 13
  • 1.簡介 數據存儲有哪些方式?電子表格,紙質文件,數據庫。 那么究竟什么是關系型數據庫? 目前對數據庫的分類主要是...
    喬震閱讀 1,764評論 0 2
  • 徹別別不離過去 傾訴訴不盡相逢 離殤殤不了依情 淚彰彰不依晨夢 花紅如血夜似瞳憧梅靜別雪艷霞隨風 夜冷心廖凡寂冥冥...
    狼眼閱讀 899評論 2 12
  • The countryside where great trees had covered for miles a...
    化真閱讀 165評論 0 1
  • 我應該在燈光幾滅的暗夜里沉沉睡去 然后在晨光微熹的清早緩緩蘇醒 外頭日光正蓄勢騰起 是每一個暖融融的早起 睜眼,起...
    枕草子_5625閱讀 132評論 0 0