SQLite | Group By 和 Order By 子句

1. Group by and Order by

我们在上一篇中介绍了 Where 子句,接下来我们将使用 Group by 和 Order by 子句,对数据进行聚合和排序。

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

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

载入 SQL 以及连接 SQLite:

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

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

首先查看 STATION_DATA 表中的数据:

%sql select * from station_data limit 0,5; -- 筛选前五行
 * sqlite:///DataBase/weather_stations.db
Done.
station_numberreport_codeyearmonthdaydew_pointstation_pressurevisibilitywind_speedtemperatureprecipitationsnow_depthfograinhailthundertornado
14308034DDA72002122133.8987.43.40.2360None11111
76644039537B199810172.71014.65.96.783.30None00000
176010C3C6D5200151855.7None7.34.369.10None00000
1256001451502007101433None6.92.539.70None00000
470160EF616A196772965.6None9.21.272.40.04None00000

1.1 Group Records

首先从最简单的聚合方法开始:计数:

%%sql
select count(*) as record_cound from station_data;
 * sqlite:///DataBase/weather_stations.db
Done.
record_cound
28000

count(*) 意味着计算记录的长度,你也可以和其他 SQL 操作符结合起来使用,比如 where,我们可以这样计算 tornado 出现的次数:

%%sql
select count(*) as record_count from station_data
where tornado == 1;
 * sqlite:///DataBase/weather_stations.db
Done.
record_count
3000

我们找到了 3000 条包含 tornado 的记录,但如果我们想要按年计数呢?我们可以这样写:

%%sql
select year, 
count(*) as record_count 
from station_data
where tornado == 1
group by year
limit 0,3; -- 只展示前三条
 * sqlite:///DataBase/weather_stations.db
Done.
yearrecord_count
19373
19413
19423

我们现在可以看到每年的计数,让我们拆分下这个查询来看看怎么执行的:

select year,              -- 1. 首先,我们选择了 year(select year)
count(*) as record_count  -- 2. 然后我们用 **count(\*)** 对筛选的记录进行了计数
from station_data
where tornado == 1        -- 3. 我们筛选了 tornado 为 true 的数据
group by year             -- 4. 最后,按年进行分类

我们也可以在多个 field 上进行聚合:

%%sql
select year, month,
count(*) as record_count
from station_data
where tornado == 1
group by year, month
limit 0,3;
 * sqlite:///DataBase/weather_stations.db
Done.
yearmonthrecord_count
193773
194183
1942103

此外,在使用 group by 时,我们可以也用 序数位置(ordinal positions):

%%sql
select year, month,
count(*) as record_count
from station_data
where tornado == 1
group by 1, 2 -- ordinal positions
limit 0,5;
 * sqlite:///DataBase/weather_stations.db
Done.
yearmonthrecord_count
193773
194183
1942103
194313
194343

不是所有的平台都支持 ordinal positions,例如 Oracle 和 SQL Server,就只能写全称

1.2 Ordering Records

需要注意到,我们通过 group 得到的数据中 month 并不是按自然月份排序的,所以字哦好就是同时使用 oreder by 操作符来进行排序,如果你想要先按年份排序,再按月份排序,你只需要添加:

%%sql
select year, month,
count(*) as record_count
from station_data
where tornado == 1
group by 1, 2 -- ordinal positions
order by 1, 2 -- order by 同样支持 ordinal positions
limit 0,5;
 * sqlite:///DataBase/weather_stations.db
Done.
yearmonthrecord_count
193773
194183
1942103
194313
194343

order by 默认是按升序(ASC)排列的,然而你可能更对近期的数据感兴趣,你可以通过添加 DESC 来指定排序方式:

%%sql
select year, month,
count(*) as record_count
from station_data
where tornado == 1
group by year, month
order by year DESC, month
limit 0,5;
 * sqlite:///DataBase/weather_stations.db
Done.
yearmonthrecord_count
201036
200913
200923
200942
200956

1.3 Aggregate Functions

我们已经使用 count(*) 来对记录进行计数了,但还有其他的一些聚合函数(AggregateyFunctions),
sum()min()max()avg()。我们可以在特定的列上使用聚合函数来进行计算。

图1 SQLite 内置聚合函数

但首先让我们来看看 count() 的另一种使用方式, count() 可以用于除了计数以外的其他用途。如果你不使用 * ,
而是指定某一列,那么它将会计算所有非缺失值(non-null)的个数。举个例子,我们可以计算 snow_depth 中非缺失值的个数:

%%sql
select count(snow_depth) as recorded_snow_depth_count
from station_data
 * sqlite:///DataBase/weather_stations.db
Done.
recorded_snow_depth_count
1552

让我们进一步看看聚合函数,如果你想要看看你从 2000 年开始每个月的平均温度,你可以先筛选 2000 年的记录,
然后按月份分组,最后计算平均温度:

%%sql
select month, avg(temperature) as avg_temp
from station_data
where year >= 2000
group by month
limit 0,3;
 * sqlite:///DataBase/weather_stations.db
Done.
monthavg_temp
141.55585443037976
238.98063127690104
348.975062656641576

sum() 是另一个常见的聚合操作符,为了得到 2000 年至今每年的下雪深度,你可以这样查询:

%%sql
select year, sum(snow_depth) as total_snow
from station_data
where year >= 2000
group by year
limit 0,3;
 * sqlite:///DataBase/weather_stations.db
Done.
yeartotal_snow
2000685.8999999999999
2001391.90000000000003
2002437.69999999999993

你可以在一次查询中多次使用聚合操作,我们将 2000 年以来的下雪总量、下雨总量和最大降雨量分别统计出来,并保留两位小数:

%%sql
select year,
round(sum(snow_depth), 2) as total_snow,
round(sum(precipitation), 2) as total_precipitation,
round(max(precipitation), 2) as max_precipitation
from station_data
where year >= 2000
group by year
limit 0,3;
 * sqlite:///DataBase/weather_stations.db
Done.
yeartotal_snowtotal_precipitationmax_precipitation
2000685.927.570.87
2001391.938.152.95
2002437.743.065.0

1.4 The Having Statement

假设你想要基于一个聚合值来筛选记录,你的第一反应应该是使用 where 子句。确实, where 子句可以
用来筛选记录,但是却无法用于聚合值上。举个例子,如果你想使用 where 子句筛选出总下雨量大于 30 的记录,
就会出现以下错误:

%%sql
select year, sum(precipitation) as total_precipitation
from station_data
where total_precipitation > 30
group by year
limit 0,3;
 * sqlite:///DataBase/weather_stations.db
(sqlite3.OperationalError) misuse of aggregate: sum()
[SQL: select year, sum(precipitation) as total_precipitation
from station_data
where total_precipitation > 30
group by year
limit 0,3;]
(Background on this error at: http://sqlalche.me/e/e3q8)

为什么不起作用呢?首先我们来看下聚合的原理,首先程序一行一行的扫描,找出那些在 where 子句
上成立的数据,然后再进行聚合。然而在聚合前并没有 total_precipitation 这一列数据,因此出错。

当你想在聚合值上执行 where 这个方法时,只能使用 having 这个关键词:

%%sql
select year,
sum(precipitation) as total_precipitation
from station_data
group by year
having total_precipitation > 30
limit 0,3
 * sqlite:///DataBase/weather_stations.db
Done.
yeartotal_precipitation
197335.07999999999996
197442.209999999999994
197548.25999999999997

having 相当于聚合版的 where,但并不是所有平台都支持在 aliases 上使用 having
如 Oracle(group by 也不行),这意味着当你使用 having 时需要再输入一次聚合函数,像这样:

%%sql
select year,
sum(precipitation) as total_preicipitation
from station_data
group by year
having sum(precipitation) > 30
limit 0,3
 * sqlite:///DataBase/weather_stations.db
Done.
yeartotal_preicipitation
197335.07999999999996
197442.209999999999994
197548.25999999999997

1.5 Getting Distinct Records

当我们使用 **select from** 时,记录中可能会包含重复值,如果你只想要返回**唯一值(distinct records)**,
你可以使用 **select distinct from**,比如我们的 station_data,表中 station_number 一列包含
了 28000 个值,但你通过 **select distinct from** 后会发现其中是 6368 个值不断重复出现组成的
%%sql
select count(station_number) as duplicate_num
from station_data;
 * sqlite:///DataBase/weather_stations.db
Done.
duplicate_num
28000
%%sql
select count(distinct station_number) as distinct_num
from station_data;
 * sqlite:///DataBase/weather_stations.db
Done.
distinct_num
6368

参考资料

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

相关文章:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值