一、语法:case when then else end
Case具有两种格式。简单Case函数和Case搜索函数。
简单Case函数
CASE sex
WHEN '1' THEN '男'
WHEN '2' THEN '女'
ELSE '其他' END
二、Case函数一些实际场景
1、已知数据按照另外一种方式进行分组
----工资等级统计
SELECT CASE
WHEN salary <= 500 THEN
'1'
WHEN salary > 500 AND salary <= 600 THEN
'2'
WHEN salary > 600 AND salary <= 800 THEN
'3'
WHEN salary > 800 AND salary <= 1000 THEN
'4'
ELSE
NULL
END salary_class, -- 别名命名
COUNT(*)
FROM Table_A
GROUP BY CASE
WHEN salary <= 500 THEN
'1'
WHEN salary > 500 AND salary <= 600 THEN
'2'
WHEN salary > 600 AND salary <= 800 THEN
'3'
WHEN salary > 800 AND salary <= 1000 THEN
'4'
ELSE
NULL
END;
2、用一个SQL语句完成不同条件的分组。
下面我们来举个例子公司A,这个公司有个规定,女职员的工资必须高于1000块。如果用Check和Case来表现的话,如下所示
THEN 1 ELSE 0 END ELSE 1 END = 1 )
如果单纯使用Check: CONSTRAINT check_salary CHECK ( sex = '2' AND salary > 1000 ) 女职员的条件倒是符合了,男职员就无法输入了。
2.工资在2000到4600之间的职员,工资增加15%
这种方法还可以在很多地方使用,比如说变更主键这种累活。
一般情况下,要想把两条数据的Primary key,a和b交换,需要经过临时存储,拷贝,读回数据的三个过程,要是使用Case函数的话,一切都变得简单多了
p_key | col_1 | col_2 |
a | 1 | 张三 |
b | 2 | 李四 |
c | 3 | 王五 |
a
和
b
相互交换。用Case函数来实现的话,代码如下
下面具个例子来说明,有两个表,tbl_A,tbl_B,两个表中都有keyCol列。现在我们对两个表进行比较,tbl_A中的keyCol列的数据如果在tbl_B的keyCol列的数据中可以找到,返回结果'Matched',如果没有找到,返回结果'Unmatched'。
要实现下面这个功能,可以使用下面两条语句
学号(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 FROM Studentclass GROUP BY std_id HAVING COUNT(*) = 1;
执行结果1
条件2
执行结果2
如果使用Case函数,我们只要一条SQL语句就可以解决问题,具体如下所示
运行结果
最后提醒一下使用Case函数的新手注意不要犯下面的错误
CASE col_1
在这个语句中When Null这一行总是返回unknown,所以永远不会出现Wrong的情况。因为这句实际表达的意思是
WHEN col_1 = NULL,这是一个错误的用法,这个时候我们应该选择用WHEN col_1 IS NULL。
7、小结
select 与 case结合使用最大的好处有两点,一是在显示查询结果时可以灵活的组织格式,二是有效避免了多次对同一个表或几个表的访问。
下面举个简单的例子来说明。例如表 students(id, name ,birthday, sex, grade),要求按每个年级统计男生和女生的数量各是多少,统计结果的表头为,年级,男生数量,女生数量。如果不用select case when,为了将男女数量并列显示,统计起来非常麻烦,先确定年级信息,再根据年级取男生数和女生数,而且很容易出错。
用select case when写法如下:
SELECT grade, COUNT (CASE WHEN sex = 1 THEN 1
ELSE NULL
END) 男生数,
COUNT (CASE WHEN sex = 2 THEN 1
ELSE NULL
END) 女生数
FROM students
GROUP BY grade;
***************************case when实际工作中的应用示例:
select a.order_id,
case a.prod_id
when 1 then
'普话'
when 140 then
'宽带'
when 482 then
'vop'
end
from t_od_recv_queue_his a;
select to_char(dtrtime, 'yyyy-mm-dd HH24:mi') 时间,
count(case when a.ineid='221' then a.ineid else null end) as 网元221 ,
count(case when a.ineid='222' then a.ineid else null end) as 网元222 ,
count(case when a.ineid='223' then a.ineid else null end) as 网元223 ,
count(case when a.ineid='224' then a.ineid else null end) as 网元224 ,
count(case when a.ineid='225' then a.ineid else null end) as 网元225 ,
count(case when a.ineid='101' then a.ineid else null end) as 网元221 ,
count(case when a.ineid='102' then a.ineid else null end) as 网元222 ,
count(case when a.ineid='103' then a.ineid else null end) as 网元223 ,
count(case when a.ineid='104' then a.ineid else null end) as 网元224 ,
count(case when a.ineid='105' then a.ineid else null end) as 网元225
from tneticket_gsm a
where a.dtrtime > to_date('2014-03-06 00:00:00', 'yyyy-mm-dd HH24:mi:ss')
-- and a.dtrtime < to_date('2014-01-15 07:00:00', 'yyyy-mm-dd HH24:mi:ss')
and a.iworkstatus=1
and a.iworkresult=0
and a.ifinishflag=0
group by to_char(dtrtime, 'yyyy-mm-dd HH24:mi')
order by to_char(dtrtime, 'yyyy-mm-dd HH24:mi');
select to_char(t.dtrtime, 'yyyymm'),
sum(case when (b.dtrtime - t.dtrtime) * 24 * 3600< 1 then 1 else 0 end) 小于S,
sum(case when (b.dtrtime - t.dtrtime) * 24 * 3600>= 1 and (b.dtrtime - t.dtrtime) * 24 * 3600< 2 then 1 else 0 end) 小于1S,
sum(case when (b.dtrtime - t.dtrtime) * 24 * 3600>= 2 and (b.dtrtime - t.dtrtime) * 24 * 3600< 3 then 1 else 0 end) 小于S,
sum(case when (b.dtrtime - t.dtrtime) * 24 * 3600>= 3 and (b.dtrtime - t.dtrtime) * 24 * 3600< 4 then 1 else 0 end) 小于2S,
sum(case when (b.dtrtime - t.dtrtime) * 24 * 3600>= 4 and (b.dtrtime - t.dtrtime) * 24 * 3600< 5 then 1 else 0 end) 小于3S,
sum(case when (b.dtrtime - t.dtrtime) * 24 * 3600>= 5 and (b.dtrtime - t.dtrtime) * 24 * 3600< 6 then 1 else 0 end) 小于4S,
sum(case when (b.dtrtime - t.dtrtime) * 24 * 3600>= 6 and (b.dtrtime - t.dtrtime) * 24 * 3600< 8 then 1 else 0 end) 小于5S,
sum(case when (b.dtrtime - t.dtrtime) * 24 * 3600>= 8 and (b.dtrtime - t.dtrtime) * 24 * 3600< 10 then 1 else 0 end) 小于6S,
sum(case when (b.dtrtime - t.dtrtime) * 24 * 3600>= 10 then 1 else 0 end) 大于6S
from tworkrelation_gsm_near t,
(select a.vcwid, max(a.dtrtime) dtrtime
from tneticket_gsm_near a
where a.dtrtime > To_Date('2013-12-01', 'yyyy-mm-dd')
and a.vcsvccode in ('101240')--开户
group by a.vcwid) b
where b.vcwid = t.vcwid
and t.dtrtime >
to_date('2013-10-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')
and t.dtrtime <
to_date('2013-10-31 23:59:59', 'yyyy-mm-dd hh24:mi:ss')
and (b.dtrtime - t.dtrtime) * 24 * 3600< 60--2min
and t.vcsla = 200
group by to_char(t.dtrtime, 'yyyymm')
order by to_char(t.dtrtime, 'yyyymm');