CASE WHEN 及 SELECT CASE WHEN的用法
种方式,可以实现相同的功能。简单Case函数的写法相对比较简洁,但是和Case搜索函数相比,功能方面会有些限制,比如写判断式。 还有一个需要注意的问题,Case函数只返回第一个符合条件的值,剩下的Case部分将会被自动忽略。
下面我们来看一下,使用Case函数都能做些什么事情。
一,已知数据按照另外一种方式进行分组,分析。
有如下数据:(为了看得更清楚,我并没有使用国家代码,而是直接用国家名作为Primary Key)
同样的,我们也可以用这个方法来判断工资的等级,并统计每一等级的人数。SQL代码如下:
二,用一个SQL语句完成不同条件的分组。
有如下数据
SELECT country,
这样我们使用Select,完成对二维表的输出形式,充分显示了Case函数的强大。
三,在Check中使用Case函数。
在Check中使用Case函数在很多情况下都是非常不错的解决方法。可能有很多人根本就不用Check,那么我建议你在看过下面的例子之后也尝试一下在SQL中使用Check。
下面我们来举个例子
公司A,这个公司有个规定,女职员的工资必须高于1000块。如果用Check和Case来表现的话,如下所示
CONSTRAINT check_salary CHECK ( CASE WHEN sex = '2' THEN CASE WHEN salary > 1000 THEN 1 ELSE 0 END ELSE 1 END = 1 )
如果单纯使用Check: CONSTRAINT check_salary CHECK ( sex = '2' AND salary > 1000 ) 女职员的条件倒是符合了,男职员就无法输入了。
例,有如下更新条件
2.工资在2000到4600之间的职员,工资增加15%
但是事情没有想象得那么简单,假设有个人工资5000块。首先,按照条件1,工资减少10%,变成工资4500。接下来运行第二个SQL时候,因为这个人的工资是4500在2000到4600的范围之内,需增加15%,最后这个人的工资结果是5175,不但没有减少,反而增加了。如果要是反过来执行,那么工资4600的人相反会变成减少工资。暂且不管这个规章是多么荒诞,如果想要一个SQL语句实现这个功能的话,我们需要用到Case函数。代码如下:
这里要注意一点,最后一行的ELSEsalary是必需的,要是没有这行,不符合这两个条件的人的工资将会被写成NUll,那可就大事不妙了。 在Case函数中Else部分的默认值是NULL,这点是需要注意的地方。
这种方法还可以在很多地方使用,比如说变更主键这种累活。
一般情况下,要想把两条数据的Primarykey,a和b交换,需要经过临时存储,拷贝,读回数据的三个过程,要是使用Case函数的话,一切都变得简单多了。
p_key | col_1 | col_2 |
a | 1 | 张三 |
b | 2 | 李四 |
c | 3 | 王五 |
a
和
b
相互交换。用Case函数来实现的话,代码如下
同样的也可以交换两个Uniquekey。需要注意的是,如果有需要交换主键的情况发生,多半是当初对这个表的设计进行得不够到位,建议检查表的设计是否妥当。
五,两个表数据是否一致的检查。
Case函数不同于DECODE函数。 在Case函数中,可以使用BETWEEN,LIKE,ISNULL,IN,EXISTS等等。比如说使用IN,EXISTS,可以进行子查询,从而 实现更多的功能。
下面具个例子来说明,有两个表,tbl_A,tbl_B,两个表中都有keyCol列。现在我们对两个表进行比较,tbl_A中的keyCol列的数据如果在tbl_B的keyCol列的数据中可以找到,返回结果'Matched',如果没有找到,返回结果'Unmatched'。
要实现下面这个功能,可以使用下面两条语句
六,在Case函数中使用合计函数
假设有下面一个表
学号(std_id) | 课程ID(class_id) | 课程名(class_name) | 主修flag(main_class_flg) |
100 | 1 | 经济学 | Y |
100 | 2 | 历史学 | N |
200 | 2 | 历史学 | N |
200 | 3 | 考古学 | Y |
200 | 4 | 计算机 | N |
300 | 4 | 计算机 | N |
400 | 5 | 化学 | N |
500 | 6 | 数学 | N |
现在我们要按照下面两个条件对这个表进行查询
1.只选修一门课程的人,返回那门课程的ID
2.选修多门课程的人,返回所选的主课程ID
简单的想法就是,执行两条不同的SQL语句进行查询。
条件1
--条件1:只选择了一门课程的学生
SELECT std_id, MAX(class_id) AS main_class FROMStudentclass GROUP BY std_id HAVING COUNT(*) =1;
执行结果1
条件2
执行结果2
如果使用Case函数,我们只要一条SQL语句就可以解决问题,具体如下所示
运行结果
最后提醒一下使用Case函数的新手注意不要犯下面的错误
CASE col_1
在这个语句中WhenNull这一行总是返回unknown,所以永远不会出现Wrong的情况。因为这句实际表达的意思是
WHEN col_1 =NULL,这是一个错误的用法,这个时候我们应该选择用WHEN col_1 ISNULL。
七、小结
select 与case结合使用最大的好处有两点,一是在显示查询结果时可以灵活的组织格式,二是有效避免了多次对同一个表或几个表的访问。
下面举个简单的例子来说明。例如表 students(id, name ,birthday, sex,grade),要求按每个年级统计男生和女生的数量各是多少,统计结果的表头为,年级,男生数量,女生数量。如果不用select casewhen,为了将男女数量并列显示,统计起来非常麻烦,先确定年级信息,再根据年级取男生数和女生数,而且很容易出错。
用select case when写法如下:
SELECT grade, COUNT (CASE WHEN sex = 1 THEN1
ELSENULL
END)男生数,
COUNT(CASE WHEN sex = 2 THEN1
ELSENULL
END)女生数
FROM students
GROUP BY grade;
*************************
最近接手的项目中需要对集体表中的男女人数做一个统计,原来的实现是通过两个查询语句做到的——SELECT * FROM student WHERE sex='男',同样也可以查询到查询到所有女生人数和总人数,暂且不说这样会多少次连接数据库造成资源的消耗和时间的浪费,就是前台的拼接数据也得费不少脑细胞吧,况且这么low的办法,肯定是有更加高效的方式的!
那么就有了case when的用武之地,case when使这一业务性能上有了巨大优化,下面就见分晓!
业务背景:
需要查询得到表中男生和女生各自的人数总和以及所有的人数;
表结构:
实现语句:
- SELECT
- COUNT(*) AS number,
- SUM(
- CASE sex
- WHEN '男' THEN
- 1
- ELSE
- 0
- END
- ) AS male,
- SUM(
- CASE sex
- WHEN '女' THEN
- 1
- ELSE
- 0
- END
- ) AS female
- FROM
- student
结果:
☆拓展:
1.已知数据按另一种方式分组、分析
--表结构:
--实现语句:
- SELECT
- SUM(population),
- CASE country
- WHEN '中国' THEN
- '亚洲'
- WHEN '印度' THEN
- '亚洲'
- WHEN '日本' THEN
- '亚洲'
- WHEN '美国' THEN
- '北美洲'
- WHEN '加拿大' THEN
- '北美洲'
- WHEN '墨西哥' THEN
- '北美洲'
- ELSE
- '其他'
- END
- FROM
- country
- GROUP BY
- CASE country
- WHEN '中国' THEN
- '亚洲'
- WHEN '印度' THEN
- '亚洲'
- WHEN '日本' THEN
- '亚洲'
- WHEN '美国' THEN
- '北美洲'
- WHEN '加拿大' THEN
- '北美洲'
- WHEN '墨西哥' THEN
- '北美洲'
- ELSE
- '其他'
- END;
--结果:
2.还有常见的对员工的工资按等级划分;
--表结构:
--sql语句:
- SELECT
- CASE
- WHEN salary <= 2000 THEN
- '一'
- WHEN salary > 2000
- AND salary <= 4000 THEN
- '二'
- WHEN salary > 4000
- AND salary <= 6000 THEN
- '三'
- WHEN salary > 6000
- AND salary <= 8000 THEN
- '四'
- ELSE
- '其他'
- END salary_class,
- COUNT(*)
- FROM
- salary
- GROUP BY
- CASE
- WHEN salary <= 2000 THEN
- '一'
- WHEN salary > 2000
- AND salary <= 4000 THEN
- '二'
- WHEN salary > 4000
- AND salary <= 6000 THEN
- '三'
- WHEN salary > 6000
- AND salary <= 8000 THEN
- '四'
- ELSE
- '其他'
- END;
--表结构:
--sql语句:
- SELECT
- country,
- SUM(
- CASE
- WHEN sex = '男' THEN
- population
- ELSE
- 0
- END
- ) AS maleNo,
- SUM(
- CASE
- WHEN sex = '女' THEN
- population
- ELSE
- 0
- END
- ) AS femaleNo
- FROM
- population
- GROUP BY
- country
--结果:
4.check中使用case
总之,case when对查询不同类别的数据会给我们提供很大的帮助,也确确实实会减少很多的消耗,提高响应速度!
*********************************
有时数据库中为了存储空间的节约,存了一些比较小的字段,这是可以在select语句中进行转换。
在select 语句中用条件语句:如果,数据库中一个字段Gender来存储性别,存的是1/0两个值,这时可以用selectcasewhen gender=1 then'Man'else'Woman'endas [gender] from PersonInfo
SQL CASE 表达式是一种通用的条件表达式,类似于其它语言中的 if/else 语句。
CASE WHEN <tt><em>condition</em></tt> THEN <tt><em>result</em></tt> [WHEN ...] [ELSE <tt><em>result</em></tt>] END
CASE 子句可以用于任何表达式可以有效存在的地方。 condition 是一个返回boolean 的表达式。 如果结果为真,那么 CASE 表达式的结果就是符合条件的 result。 如果结果为假,那么以相同方式搜寻任何随后的 WHEN 子句。 如果没有 WHEN condition 为真,那么 case 表达式的结果就是在 ELSE 子句里的值。 如果省略了 ELSE 子句而且没有匹配的条件, 结果为 NULL。
例子:
SELECT * FROM test; a --- 1 2 3 SELECT a, CASE WHEN a=1 THEN 'one' WHEN a=2 THEN 'two' ELSE 'other' END FROM test; a | case ---+------- 1 | one 2 | two 3 | other
所有 result 表达式的数据的类型都必须可以转换成单一的输出类型。
下面这个"简单的" CASE 表达式是上面的通用形式的一个特殊的变种。
CASE <tt><em>expression</em></tt> WHEN <tt><em>value</em></tt> THEN <tt><em>result</em></tt> [WHEN ...] [ELSE <tt><em>result</em></tt>] END
先计算 expression 的值, 然后与所有在WHEN 子句里声明的 value 对比,直到找到一个相等的。 如果没有找到匹配的,则返回在 ELSE 子句里的 result (或者 NULL)。 这个类似于 C 里的 switch
语句。
上面的例子可以用简单 CASE 语法来写:
SELECT a, CASE a WHEN 1 THEN 'one' WHEN 2 THEN 'two' ELSE 'other' END FROM test; a | case ---+------- 1 | one 2 | two 3 | other
CASE 表达式并不计算任何对于判断结果并不需要的子表达式。 比如,下面是一个可以避免被零除的方法:
SELECT ... WHERE CASE WHEN x <> 0 THEN y/x > 1.5 ELSE false END;
以下是case when 实例:
- SELECT dbo.FM_InHospital_Fee.EMPI_ID AS p_main_id, dbo.FM_InHospital_Fee.Inhosp_No AS p_settlement_code, dbo.FM_InHospital_Fee.Pat_Name AS p_name,
- dbo.PA_Patient_Information.Sex_Name AS p_sex, dbo.FM_InHospital_Fee.Inhosp_Index_No AS p_admit_id,
- dbo.PA_Inhospital_Registration.MR_No AS p_medical_record_id, dbo.FM_InHospital_Fee.Curr_Dept_Code AS p_admit_dept_code,
- dbo.FM_InHospital_Fee.Curr_Dept_Name AS p_admit_dept_name, dbo.PA_Inhospital_Registration.Admit_Bed_No AS p_admit_bed_no,
- dbo.PA_Inhospital_Registration.Admit_Date AS p_admit_date, dbo.PA_Inhospital_Registration.Discharge_Date AS p_discharge_date, '' AS p_admit_days,
- dbo.FM_InHospital_Fee.Medicare_Categ_Name AS p_medicare_type, dbo.PA_Patient_Information.HC_No AS p_social_security_id,
- dbo.FM_InHospital_Fee.Charge_Date AS p_settlement_date, dbo.FM_InHospital_Fee.Settlement_Staff_Name AS p_settlement_person, '' AS p_personal_fee,
- '' AS p_medicare_fund_payment, '' AS p_accept_fee, '' AS p_pay_fee, '' AS p_expect_fee, CASE WHEN Charge_Item_Code = 'BILL03' THEN 'Receivable_Fee' ELSE NULL
- END AS p_western_medicine_fee, CASE WHEN Charge_Item_Code = 'BILL04' THEN 'Receivable_Fee' ELSE NULL END AS p_chinese_patent_medicine_fee,
- CASE WHEN Charge_Item_Code = 'BILL05' THEN 'Receivable_Fee' ELSE NULL END AS p_chinese_herbal_medicine_fee,
- CASE WHEN Charge_Item_Code = 'BILL06' THEN 'Receivable_Fee' ELSE NULL END AS p_inspect_fee,
- CASE WHEN Charge_Item_Code = 'BILL08' THEN 'Receivable_Fee' ELSE NULL END AS p_irradiation_fee,
- CASE WHEN Charge_Item_Code = 'BILL10' THEN 'Receivable_Fee' ELSE NULL END AS p_assay_fee,
- CASE WHEN Charge_Item_Code = 'BILL07' THEN 'Receivable_Fee' ELSE NULL END AS p_treatment_fee,
- CASE WHEN Charge_Item_Code = 'BILL09' THEN 'Receivable_Fee' ELSE NULL END AS p_operation_fee,
- CASE WHEN Charge_Item_Code = 'BILL11' THEN 'Receivable_Fee' ELSE NULL END AS p_oxygen_therapy_fee,
- CASE WHEN Charge_Item_Code = 'BILL01' THEN 'Receivable_Fee' ELSE NULL END AS p_medical_fee,
- CASE WHEN Charge_Item_Code = 'BILL02' THEN 'Receivable_Fee' ELSE NULL END AS p_bed_fee,
- CASE WHEN Charge_Item_Code = 'BILL12' THEN 'Receivable_Fee' ELSE NULL END AS p_other_fee, '' AS p_material_fee, '' AS p_intensive_care_fee,
- '' AS p_transfusion_fee, '' AS p_nurse_fee, dbo.FM_InHospital_Fee.Total_Fee AS p_add_fee
- FROM dbo.FM_InHospital_Fee INNER JOIN
- dbo.PA_Patient_Information ON dbo.FM_InHospital_Fee.EMPI_ID = dbo.PA_Patient_Information.EMPI_ID INNER JOIN
- dbo.PA_Inhospital_Registration ON dbo.FM_InHospital_Fee.EMPI_ID = dbo.PA_Inhospital_Registration.EMPI_ID
给客户做列表新增的时候,有个需求:根据广告类型从不同的表查询数据,保存到数据库。代码如下所示:
<div class="form-group" id="adType">
<label>类型:</label>
<select id='itemType' name="itemType">
<option value="">请选择</option>
<option value="1">资讯</option>
<option value="2">商品</option>
<option value="3">店铺</option>
<option value="4">网页</option>
</select>
</div>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
资讯 (带搜索的下拉框) 1
Information 从information表中取ID和title del_flag为0的
/pet/web/information/information-web!getInfoSelectData
- 1
商品(搜索的下拉框) 2
goods 从goods表中取ID和name del_flag为0的
/pet/web/goods/goods-web!getGoodsSelectData
- 1
店铺(搜索的下拉框) 3
store 从store表中取ID和name audit_Type为1的(已审核)
/pet/web/store/store-web!getStoreSelectData
- 1
网页(输入链接地址)4 手动输入
综上所述,需要根据itemType的值从不同的数据库获取item_id的值。
下面是查询的语句,通过case when在MySQL中查询
(case
when (item_type = '1') then
(select i.title from information i where i.id = item_id)
when (item_type = '2') then
(select g.name from goods g where g.id = item_id)
when (item_type = '3') then
(select s.name from store s where s.id = item_id)
WHEN (item_type = '4') THEN
item_id
end
) as goodsName,
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
大功告成!第一次使用case when。
************
示例一
SELECT 学号, 姓名,
等级=
CASE
WHEN 总学分 IS NULL THEN ‘尚未选课’
WHEN 总学分 < 50 THEN ‘不及格’
WHEN 总学分 >=50 and 总学分<=52 THEN ‘合格’
ELSE ‘优秀’
END FROM XS WHERE 专业名=’计算机’
示例二
update employee
set e_wage =
case
when job_level = ’1’ then e_wage*1.08
when job_level = ’2’ then e_wage*1.07
when job_level = ’3’ then e_wage*1.06
else e_wage*1.05
end
示例三
select a, (case a when 1 then '中' else '国' end) AS B from table1