数据类型

某些聚合函数可以作用于所有数据类型,例如COUNT;而某些聚合函数只能作用于特点数据类型,例如SUM只能作用于数值类型。某些数据看起来是数值,但是很可能是以VARCHAR形式存储的。这就涉及到了数据类型的转换。可以采用以下两种形式。

CAST(column_name AS integer)
column_name::integer

我们注意到在Date数据类型中,年是放在最前面的,采用YYYY-MM-DD的格式。这是为了我们在排序的时候更加方便。即便有些日期是以String形式存储的,按照这个格式进行排序,依然不会出错。

在进行日期计算的时候,可以使用Interval函数进行加工,例如

company.founded_date <= company.bankruptcy_date + INTERVAL '5 years'

字符串函数

截断字符串

LEFT(string, number of characters)
RIGHT(string, number of characters)
SUBSTR(string, starting position, length)

拼接字符串

CONCAT函数将不同字符串进行拼接,括号内字符串个数是任意的。我们也可以使用’||'进行拼接。

CONCAT(str1, str2, str3, ...)
str1 || str2 || str3

取长度

LENGTH(string)

修剪

将字符串首尾两段某些字符删除掉。第一个参数填写需要去除的位置,‘leading’、‘trailing’、'both’分别代表只删除前面/后面/两端的字符。第二个参数填写需要被去掉的字符。第三个参数填写字段。

TRIM(both '()' FROM location)

位置

找出某个子串在字段中的起始位置,被查找的子串区分大小写。有以下两种写法,目前mysql支持第一种写法。

SELECT name, POSITION('o' IN name)
SELECT name, STRPOS(name, 'o')

大小写转换

UPPER(string)
LOWER(string)

时间

可以使用EXTRACT函数提取有用的时间段。

DATE_TRUNC函数将日期四舍五入到指定的精度。显示的值是该时间段的第一个值。因此,当DATE_TRUNC by year时,该年份的任何值都会被列出为该年份的1月1日。

SELECT cleaned_date,EXTRACT('year'   FROM cleaned_date) AS year,EXTRACT('month'  FROM cleaned_date) AS month,EXTRACT('day'    FROM cleaned_date) AS day,EXTRACT('hour'   FROM cleaned_date) AS hour,EXTRACT('minute' FROM cleaned_date) AS minute,EXTRACT('second' FROM cleaned_date) AS second,EXTRACT('decade' FROM cleaned_date) AS decade,EXTRACT('dow'    FROM cleaned_date) AS day_of_week
FROM criminals;-- 选择时区
SELECT CURRENT_TIME AS time,CURRENT_TIME AT TIME ZONE 'PST' AS time_pst;

填充

使用COALESCE函数对空值进行填充。

SELECT id, name, COALESCE(descript, 'No Description')
FROM medicine;

子查询

子查询必须具有名称,这些名称会在括号后添加,就像在普通表中添加别名一样。如果嵌套许多子查询,不需要一直缩进到括号以内,仅缩进两个左右的空格即可。

多阶段聚合

我们需要的查询结果需要经历多次聚合,则每一次聚合需要采用一层子查询。例如,我们想知道平均每个月事故发生的总量:首先对每天的数据进行聚合,第二步再取平均值。

SELECT MONTH(sub.date), AVG(sub.counts) AS avg_per_month
FROM (SELECT i.date, COUNT(*) AS countsFROM incidents AS iGROUP BY i.date
) sub
GROUP BY MONTH(sub.date)
ORDER BY MONTH(sub.date);

条件逻辑中的子查询

在条件逻辑中使用子查询,经常会搭配MIN或者MAX函数使用。如果子查询会返回多个查询结果,则前面只能使用IN。

SELECT * FROM incidents i
WHERE i.date = (SELECT MIN(date)FROM incidents
);

请注意,在条件语句中编写子查询时,不应包含别名。这是因为子查询被视为单个值(或IN情况下的一组值),而不是一个表。

联接子查询

我们可以联接一个与外部查询命中相同表的子查询,而不是在WHERE子句中进行过滤。

SELECT i.*, sub.date, sub.counts FROM incidents i
WHERE incidents JOIN (SELECT date, COUNT(*) countsFROM incidentsGROUP BY date
) sub
ON i.date = sub.date
ORDER BY sub.counts DESC;

也会经常搭配UNION使用。

SELECT COUNT(*) AS total_rows
FROM (SELECT * FROM investments_part1UNION ALLSELECT * FROM investments_part2
) sub

窗口函数

窗口函数跨一组与当前行相关的表行执行计算。这相当于可以使用聚合函数完成的计算类型。但是,与常规聚合函数不同,使用窗口函数不会导致不同单独的行被分组之后成为单个输出行,而是保持行的独立标识。在后台,窗口功能可以访问的不只有查询结果的当前行。

接下来,我们使用一个例子进行讲解。数据来源于Capital bike公司的公用数据。这里有一个我清理过后的版本:数据。

建表使用语句,

CREATE TABLE `biking_records` (`Duration` INT(11) NULL DEFAULT NULL,`Start_time` DATETIME NULL DEFAULT NULL,`End_time` DATETIME NULL DEFAULT NULL,`Start_station` VARCHAR(200) NULL DEFAULT NULL,`End_station` VARCHAR(200) NULL DEFAULT NULL,`Bike_id` VARCHAR(50) NULL DEFAULT NULL,`Member_type` VARCHAR(20) NULL DEFAULT NULL
)
ENGINE=InnoDB
;

建表之后,将csv文件导入。

我们使用的案例sql语句见下,

SELECT duration, SUM(duration) OVER (ORDER BY start_time) AS running_total
FROM biking_records;

语法

注意,我们不能在同一个查询中使用窗口函数和聚合函数。更具体地说,是不能在GROUP BY子句中包含窗口函数。

如果想将范围从整个数据集缩小到独立组内的数据集,我们可以使用PARTITION。例如下面这个查询,根据起始站对查询进行分组和排序,逐渐累加骑行时间。在同一个起始站的每个值中,按照起始时间排序。

SELECT start_station, duration,SUM(duration) OVER (PARTITION BY start_station ORDER BY start_time) AS running_total
FROM biking_records
WHERE start_time < '2012-01-08'

如果我们将ORDER BY start_time删除,我们会发现每个起始站的running_total值都变成一样的了,即该起始站的duration的总合。

我们再用一个例子来熟悉一下。

SELECT start_station, duration,SUM(duration) OVER  (PARTITION BY start_station ORDER BY start_time) AS running_total,COUNT(duration) OVER (PARTITION BY start_station ORDER BY start_time) AS running_count,AVG(duration) OVER (PARTITION BY start_station ORDER BY start_time) AS running_avg
FROM biking_records;

效果如下(只是返回结果最前面一部分)。

如果将例子中的ORDER BY全部去掉,产生的效果如下。

标记行号函数

ROW_NUMBER()显示给定行的编号,从1开始。如果配合PARTITION BY使用,则会在每个区域内重新开始编号。括号内即便没有PARTITION BY也必须有ORDER BY子句。

该函数在mysql 8.0之前无法使用。

SELECT start_station, start_time, duration,                                       ROW_NUMBER() OVER (PARTITION BY start_station ORDER BY start_time) AS row_number
FROM biking_records;

排名函数

RANK()函数和ROW_NUMBER()其实非常类似。唯一的区别是在对于ORDER BY子句出现并列情况的处理。比如上面的查询对于start_time进行排序,如果两条记录start_time相同,那么两条记录ROW_NUMBER()并不相同(具有唯一性),而RANK()则会返回一样的值(允许排名相同)。

需要注意的是RANK()函数严格遵循排名算法,即假设最开始的两条记录并列,则第三条记录的排名为3。换言之,数据中将不存在排名为2的记录。如果我们不希望这种情况发生(即不跳过任何排名数字),可以使用DENSE_RANK()函数。

分位数函数

NTILE()函数可以知道当前记录在总体情况中的分位数。不过该函数使用频率并不高。

SELECT start_station, duration,
NTILE(4) OVER (PARTITION BY start_station ORDER BY duration) as quartile,
NTILE(100) OVER (PARTITION BY start_station ORDER BY duration) as percentile
FROM biking_records
ORDER BY start_station, duration;

临近记录比较函数

经常有需求是将当前行与前一行或后一行进行比较。LAG()函数可以与前面的行进行比较,LEAD()函数可以与后面的行进行比较。

例如,我们想知道两条骑行记录的持续时间之间的差值,可以使用如下查询。

SELECT start_station, duration,duration - LAG(duration, 1) OVER(PARTITION BY start_station ORDER BY duration) AS difference
FROM biking_records
ORDER BY start_station, duration;

从上图可以发现,因为第一行之前并没有记录,所以默认值是NULL,则在第一行的difference列显示的也是NULL。在实际查询中,我们可以根据需求进行保留或者通过以在外面包装一层查询的方式去除。

窗口别名

当多个窗口函数需要用到相同条件的时候,我们可以使用WINDOW给该条件起一个别名,已达到简化查询的效果。例如,参照之前分位数的查询,我们可以简化如下。

SELECT start_station, duration,
NTILE(4) OVER ntile_window as quartile,
NTILE(100) OVER ntile_window as percentile
FROM biking_records
WINDOW ntile_window AS (PARTITION BY start_station ORDER BY duration)
ORDER BY start_station, duration;

Reference

  • Mode SQL Tutorial

进阶SQL技巧:subquery, string function, window function相关推荐

  1. mysql8 create table 语法错误_MySQL8.0 Window Function 剖析

    title: $MySQL8.0 Window Functions 剖析 author: $马腾 什么是window function window function 是在满足某种条件的记录集合上执行 ...

  2. !function($){}(window.jQuery) 是什么意思

    !function($){}(window.jQuery)是什么意思. 求详细解释. JavaScript code 就是返回值取反,等价(function(){})()匿名函数直接执行了,只是用取反 ...

  3. 窗口函数(Window Function)

    文章目录 窗口函数概述 窗口函数和聚合函数的区别 使用要点 应用场景 语法结构 非聚合窗口函数 rank dense_rank row_number cume_dist percent_rank fi ...

  4. 1.20_Flink的Window全面解析\Keyed Windows\Window Assigners\Tumbling,Sliding,Session,Global,Window Function

    1.20.透过窗口看无限数据流----Flink的Window全面解析 1.20.1.Quick Start 1.20.1.1.是什么? 1.20.1.2.如何用? 1.20.1.2.1.Keyed ...

  5. Vue父组件调用子组件的方法并传参的两种方式(用$refs.refName.functionName、window.function)

    如需了解儿子怎么控制老子的,传送门:https://s-z-q.blog.csdn.net/article/details/120094689 父组件father.vue <template&g ...

  6. jquery插件开发;(function ( $, window, document, undefined ){}(jQuery, window,document)分析

    经常看到许多jquery插件是这种形式: ;(function( $, window, document, undefined ){}){//...code }(jquery,window,docum ...

  7. 【Android 逆向】IDA 工具使用 ( 函数窗口 Function window | 创建引用图 Xrefs graph to | 创建调用图 Xrefs graph from )

    文章目录 一.函数窗口 Function window 二.创建引用图 Xrefs graph to 三.创建调用图 Xrefs graph from 一.函数窗口 Function window 左 ...

  8. JS 关于(function( window, undefined ) {})(window)写法的理解

    (function( window, undefined ) {})(window); 这个,为什么要将window和undefined作为参数传给它? (function( $, undefined ...

  9. window. onload=function(){} 与 $(function(){}) 的区别

    页面加载事件:window.οnlοad=function(){} 和 $(function(){}); 1.window.οnlοad=function(){}是js原生的事件: 2.$(funct ...

最新文章

  1. 学了编译原理能否用 Java 写一个编译器或解释器?
  2. 简单的聊聊自动化测试:Selenium的高级操作
  3. ubuntu系统debootstrap的使用
  4. Wireshark:Usage in Ubuntu 18.04 distribution
  5. kohana中的路由规则
  6. Android数据绑定框架DataBinding用法
  7. 表3.5 文章管理测试用例表_本地管理表空间管理机制
  8. There is no getter for property named 'XXX' in class 'aaa.bbb.ccc'(终极骚操作的解决方法)...
  9. java 怎么调用js代码_在Java中直接调用js代码
  10. 第一公会强势分析《TmoLand》快速回本玩法
  11. 大佬 Python 对阵新秀 Julia ,谁能问鼎机器学习和数据科学?
  12. 【转】Unity利用WWW http传输Json数据
  13. [py]flask从0到1-模板/增删改查
  14. 线性代数知识点总结——矩阵乘法、矩阵运算与性质、矩阵微积分
  15. Spring AOP 术语
  16. js发布订阅原理,代码解析
  17. css display:flex详解
  18. 强化学习gym的使用之mountaincar的训练
  19. 信号能量密度公式_信号时频分析方法汇总
  20. 拨号服务器是什么,有什么用处?

热门文章

  1. Docker入门(三) - 搭建mysql
  2. 【排序】冒泡排序算法
  3. Filemanager 的使用
  4. 你知道我今天为什么来公司上班吗?
  5. Mc神秘·音乐-舞曲网
  6. 2.1.3 码元、波特、速率、带宽
  7. FPGA设计中MEMORY型数据怎么综合到blockRAM里面
  8. 频谱细化(补零、zfft、czt)
  9. 建空列表list,数组array,矩阵matrix
  10. 根据excel中的容填写信息