SQLite | Case 子句


相关文章:

SQL | 目录

SQLite | Select

SQLite | Where

SQLite | Group by and Order by

1. The CASE Statement

我们在上一篇中介绍了 Group by 和 Order by
接下来我们将使用 CASE 语句为符合不同条件的情况赋值。

  • 使用Jupyter Notebook 运行 SQL 语句需安装 ipython-sql

  • %sql 以及 %%sql 为在 Notebook 中运行 SQL 语句,在 SQLite 命令行或 SQLite Stiduo 中不需要 %sql 或 %%sql

载入 SQL 以及连接 SQLite:

本文将使用 weather_stations.db 数据库,其中包含了 STATION_DATA 表。

%load_ext sql
%sql sqlite:///DataBase/weather_stations.db
'Connected: @DataBase/weather_stations.db'

1.1 The CASE Statement

一个 case 语句可以让我们让我们为每一个不同的条件语句匹配不同的值。
在使用时,你可以以 case 开始,以 end 结束,在这中间,你能用
where [condiction] then [value] 的表达来为不同条件赋值。
在你指定了不同的 condiction-value 组合后,还可以用 else 为没有符合任何条件的
值指定一个默认值。举个例子,我们可以将 wind_speed 归入 wind_severity 类,大于 40
的为 HIGH,30 至 40 为 MODERATE,其他的都为 LOW:

%%sql
select report_code, year, month, day, wind_speed,
case
    when wind_speed >= 40 then 'HIGH'
    when wind_speed >= 30 and wind_speed < 40 then 'MODERATE'
    else 'LOW'
end as wind_severity
from station_data
limit 0,5;
 * sqlite:///DataBase/weather_stations.db
Done.
report_codeyearmonthdaywind_speedwind_severity
34DDA7200212210.2LOW
39537B19981016.7LOW
C3C6D520015184.3LOW
145150200710142.5LOW
EF616A19677291.2LOW

事实上,我们可以忽略 AND wind_speed < 40 这个条件,因为 sql 从上至下读取 case 语句,
那些符合 wind_speed >= 40 的记录已经被赋值为 HIGH 并且不再进行第二个条件的判断了,
所以能够到达第二个条件语句的记录必然是 wind_speed < 40* 的,因此可以简写为:

%%sql
select report_code, year, month, day, wind_speed,
case
    when wind_speed >= 40 then 'HIGH'
    when wind_speed >= 30 then 'MODERATE'
    else 'LOW'
end as wind_severity
from station_data
limit 0,5;
 * sqlite:///DataBase/weather_stations.db
Done.
report_codeyearmonthdaywind_speedwind_severity
34DDA7200212210.2LOW
39537B19981016.7LOW
C3C6D520015184.3LOW
145150200710142.5LOW
EF616A19677291.2LOW

当你创建 case 语句时,还可以同时做一些强大的转换。如使用 group by 语句对数据进行分组:

%%sql
select year,
case
    when wind_speed >= 40 then 'HIGH'
    when wind_speed >= 30 then 'MODERATE'
    else 'LOW'
end as wind_severity,
count(*) as record_count
from station_data
group by 1,2
limit 0,5;
 * sqlite:///DataBase/weather_stations.db
Done.
yearwind_severityrecord_count
1930LOW5
1932LOW3
1933LOW6
1935LOW2
1936LOW18

1.2 The “Zero/Null” CASE Trick

在使用 case 语句时,还有一些奇技淫巧,如 “zero/null” CASE 技巧,让你能够
在一个 select 语句内实现在不同的聚合值上进行分组,这是你使用 where 所无法达到的。
因为 where 只能够在所有值上判断同一个条件,而 case 能够每一种聚合值创建不同的条件语句。

假如说你想要将总降雨量 precipitation 分为两列:有龙卷风时的总降雨量(tornado_precipitation)
和没有龙卷风时的总降雨量(non_tornado_precipitation),然后按年月分组。这个逻辑需要用到两列数据:
precipitation 和 tornado,但是你会怎么编写代码呢?

如果让你写的话,你就会发现无法在一个 where 语句中完成,除非将它们拆分为两个 where语句,一个是
有龙卷风的,一个是没有龙卷风的:

%%sql
select year, month,
sum(precipitation) as tornado_precipitation
from station_data
where tornado == 1
group by year, month
limit 0, 5;
 * sqlite:///DataBase/weather_stations.db
Done.
yearmonthtornado_precipitation
19377None
194180.30000000000000004
1942100
19431None
194340.15000000000000002
%%sql
select year, month,
sum(precipitation) as non_tornado_precipitation
from station_data
where tornado == 0
group by year, month
limit 0, 5;
 * sqlite:///DataBase/weather_stations.db
Done.
yearmonthnon_tornado_precipitation
193060
193010None
193230
193330
19337None

然而我们可以用一个 case 语句将这两个查询合并为一个,你可以将判断是否有龙卷风的语句从
where 移到 case,并为不符合条件的赋值为 0,然后使用 sum 就可以了:

我们在使用 sum 聚合语句时,通过使不符合条件的值为 0 ,从而让它不被算入 sum(因为加一个 0 相当于没加)

%%sql
select year, month, 
sum(case when tornado == 1 then precipitation else 0 end) 
    as tornado_precipitation,
sum(case when tornado == 0 then precipitation else 0 end) 
    as non_tornado_precipitation
from station_data
group by year, month
limit 0,5;
 * sqlite:///DataBase/weather_stations.db
Done.
yearmonthtornado_precipitationnon_tornado_precipitation
1930600
1930100None
1932300
1933300
193370None

case 语句还可以做一些更复杂的聚合任务,如在使用 minmax 操作时,
可以使用 null 值来代替那些不符合条件的值(而不是 0)。如我们可以找出在有无龙卷风条件下的年最大降雨量:

%%sql
select year,
max(case when tornado==0 then precipitation else null end) 
    as max_non_tornado_precipitation,
max(case when tornado==1 then precipitation else null end)
    as max_tornado_precipitation
from station_data
group by year
limit 5 OFFSET 60;
 * sqlite:///DataBase/weather_stations.db
Done.
yearmax_non_tornado_precipitationmax_tornado_precipitation
19921.51.51
19931.182.13
19941.261.16
19950.910.35
19963.310.68

就像 where 子句一样,你可以在 case 子句中使用布尔表达式(包含 and, or, not)。

你可以使用以下代码来查询 2000 年后有[下雨或冰雹]时每个月的平均气温:

%%sql
select month,
avg(case when rain or hail then temperature else null end)
    as avg_precipitation_temp,
avg(case when NOT (rain or hail) then temperature else null end)
    as avg_non_precipitation_temp
from station_data
where year > 2000
group by month
limit 0,5;
 * sqlite:///DataBase/weather_stations.db
Done.
monthavg_precipitation_tempavg_non_precipitation_temp
135.62424242424242541.794149908592324
233.80243902439024638.9016233766234
346.6133333333333249.22558823529411
449.0291666666666752.33038194444437
555.8977777777777858.90691489361702

参考资料

[1] Thomas Nield.Getting Started with SQL[M].US: O’Reilly, 2016: 47-52

相关文章:

SQL | 目录
SQLite | SQLite 与 Pandas 比较篇之一
SQLite | Select 语句
SQLite | Where 子句
SQLite | Group by 与 Order by 子句
SQLite | Join 语句
SQLite | 数据库设计与 Creat Table 语句
SQLite | Insert、Delete、Updata 与 Drop 语句

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值