MySQL实现常用分析函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL实现常用分析函数相关的知识,希望对你有一定的参考价值。

参考技术A 分别在 mysql5.7.25-log 和 8.0.16 环境中实现类似Oracle的分析函数(8.0版本中已支持,直接使用即可)。
一、创建测试数据
二、row_number() over()
三、rank() over()
四、dense_rank() over()
五、lag() over()
六、lead() over()
七、待补充

例1:不分组,全部数据添加序列号,类Oracle 的rownum伪列

例2:先按roomid分组,再按照deviceid,counter排序,类Oracle 的row_number() OVER(PARTITION BY ORDER BY )

例1:不分组,全部数据按 roomid 排序,再添加序号,类Oracle 的rank() OVER(ORDER BY)

例2:先按roomid分组,再按deviceid排序,类Oracle 的rank() OVER(PARTITION BY ORDER BY)

例1:不分组,全部数据按roomid排序,再添加序号,类Oracle 的dense_rank() OVER(ORDER BY)

例2:先按roomid分组,再按deviceid排序,类Oracle 的dense_rank() OVER(PARTITION BY ORDER BY)

例1:不分组,全部数据按roomid,deviceid升序排序,类Oracle 的lag() OVER(ORDER BY)

例2:先按roomid分组,再按roomid,deviceid排序,类Oracle 的lag() OVER(PARTITION BY ORDER BY)

例1:不分组,全部数据按roomid,deviceid,counter升序排序,类Oracle 的lead() OVER(ORDER BY)

例2:先按roomid分组,再按deviceid,counter排序,类Oracle 的lead() OVER(PARTITION BY ORDER BY)

Mysql 常用时间函数(上)

也是做数据分析嘛, SQL 必然是每天都要用的, 然后在分析中, 时间是数据分析中极为重要的部分, 可以说是承上启下或者是贯穿整个分析. 比如, 日, 周, 月, 季度, 年度 与之相对应的 环比, 同比 等基础指标都是与时间相关的, 其重要性可见一斑. 虽然各个主流的商业数据库写法有差异, 但基本都差不多的, 这里就用 Mysql 作为演示了, 虽然主要用 IQ Sybase 这个列数据库更多一些.

然而往往这些时间字段, 都质量不高, 需要额外去处理, 比如, 字符串时间, 精确到秒的时间, 时间需要提取, 时间需要计算, 周, 月等各种操作. 每次是现查, 于是这里打算来小小整理一波, 也是做个笔记方便自己查. 就好比今天有个面谈, 问我 SVM 的目标函数, 推导啥的, 我的确是一点点推导过的, 但现场就是忘了, 一点也想不起来, 我觉得也没关系, 看下自己笔记, 然后一行行公式解释出来, 也是可以的嘛, 都是自己的笔记, 为啥就不能查阅下呢,面谈来整, 确实有点压力哦...

当前时刻 now()

mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2020-07-16 23:30:15 |
+---------------------+
1 row in set (0.00 sec)

mysql> select curtime();
+-----------+
| curtime() |
+-----------+
| 23:30:09  |
+-----------+
1 row in set (0.00 sec)

当前日期 年-月-日 curdate( )

mysql> select curdate();
+------------+
| curdate()  |
+------------+
| 2020-07-16 |
+------------+
1 row in set (0.00 sec)

将字符串时间转为 年-月-日 date( )

mysql> select date(‘2020-07-16‘);
+--------------------+
| date(‘2020-07-16‘) |
+--------------------+
| 2020-07-16         |
+--------------------+
mysql> select date(‘2020-07-16 22:22:22‘);
+-----------------------------+
| date(‘2020-07-16 22:22:22‘) |
+-----------------------------+
| 2020-07-16                  |
+-----------------------------+
1 row in set (0.00 sec)

时间转字符串 date_format()

mysql> select date_format(now(), ‘%Y-%m-%d‘);
+--------------------------------+
| date_format(now(), ‘%Y-%m-%d‘) |
+--------------------------------+
| 20-07-16                       |
+--------------------------------+
1 row in set (0.00 sec)

字符串转时间 str_to_date()

+------------------------------------------+
| str_to_date(‘2016-01-02‘, ‘%Y-%m-%d %H‘) |
+------------------------------------------+
| 2016-01-02 00:00:00                      |
+------------------------------------------+
1 row in set (0.00 sec)

时间 / 时间戳互转

mysql> select unix_timestamp(now());
+-----------------------+
| unix_timestamp(now()) |
+-----------------------+
|            1594914762 |
+-----------------------+
1 row in set (0.00 sec)

mysql> select from_unixtime(1594914762);
+---------------------------+
| from_unixtime(1594914762) |
+---------------------------+
| 2020-07-16 23:52:42       |
+---------------------------+
1 row in set (0.02 sec)

字符串 / 时间戳互转

mysql> select unix_timestamp(‘2020-07-16‘);
+------------------------------+
| unix_timestamp(‘2020-07-16‘) |
+------------------------------+
|                   1594828800 |
+------------------------------+
1 row in set (0.00 sec)

mysql> select from_unixtime(1594828800, ‘%Y-%d‘);
+------------------------------------+
| from_unixtime(1594828800, ‘%Y-%d‘) |
+------------------------------------+
| 2020-16                            |
+------------------------------------+
1 row in set (0.00 sec)

mysql> select from_unixtime(1594828800, ‘%Y-%m-%d‘);
+---------------------------------------+
| from_unixtime(1594828800, ‘%Y-%m-%d‘) |
+---------------------------------------+
| 2020-07-16                            |
+---------------------------------------+
1 row in set (0.00 sec)

给时间加一个增量 date_add( ) 和 adddate( )

  • ADDDATE(date, INTERVAL expr, unit)
mysql> select date_add(‘2020-07-16‘, interval 10 day);
+-----------------------------------------+
| date_add(‘2020-07-16‘, interval 10 day) |
+-----------------------------------------+
| 2020-07-26                              |
+-----------------------------------------+
mysql> select date_add(‘2020-07-16‘, interval 1 week);
+-----------------------------------------+
| date_add(‘2020-07-16‘, interval 1 week) |
+-----------------------------------------+
| 2020-07-23                              |
+-----------------------------------------+
1 row in set (0.00 sec)

mysql> select date_add(‘2020-07-16‘, interval 1 month);
+------------------------------------------+
| date_add(‘2020-07-16‘, interval 1 month) |
+------------------------------------------+
| 2020-08-16                               |
+------------------------------------------+
1 row in set (0.00 sec)

如果不指定时间间隔, 则默认单位为 day

+-------------------------+
| adddate(‘2020-7-16‘, 4) |
+-------------------------+
| 2020-07-20              |
+-------------------------+
1 row in set (0.00 sec)

mysql> select adddate(curdate(), 4);
+-----------------------+
| adddate(curdate(), 4) |
+-----------------------+
| 2020-07-20            |
+-----------------------+
1 row in set (0.00 sec)

加法和减法, 其实都是加法.

mysql> select adddate(curdate(), -4);
+------------------------+
| adddate(curdate(), -4) |
+------------------------+
| 2020-07-12             |
+------------------------+
1 row in set (0.02 sec)

mysql> select adddate(curdate(), -33);
+-------------------------+
| adddate(curdate(), -33) |
+-------------------------+
| 2020-06-13              |
+-------------------------+
1 row in set (0.00 sec)

一定要写减, 用 date_sub(date, INTERVAL expr unit) 也行, 强迫症的话.

mysql> select date_sub(‘2020-7-16‘, interval 4 day);
+---------------------------------------+
| date_sub(‘2020-7-16‘, interval 4 day) |
+---------------------------------------+
| 2020-07-12                            |
+---------------------------------------+
1 row in set (0.00 sec)

mysql> select date_sub(‘2020-7-16‘,  interval 33 day);
+-----------------------------------------+
| date_sub(‘2020-7-16‘,  interval 33 day) |
+-----------------------------------------+
| 2020-06-13                              |
+-----------------------------------------+
1 row in set (0.00 sec)

计算日期是当年的第几周 week( )

  • week(date, mode)
mysql> select week(‘2020-01-05‘);
+--------------------+
| week(‘2020-01-05‘) |
+--------------------+
|                  1 |
+--------------------+
1 row in set (0.00 sec)

mysql> select week(date(‘2020-01-05‘));
+--------------------------+
| week(date(‘2020-01-05‘)) |
+--------------------------+
|                        1 |
+--------------------------+
1 row in set (0.00 sec)

mysql 是正常的, 一周是从 周1 到周天. 而像 IQ Sybase 就是西式的. 然后要自己写一个 case when.

-- IQ
set datefirst 1; 
select 
	case 
		when datepart(weekday, 日期字段) = 7 
			then datepart(week, dateadd(day, -1, 日期字段)) 
		else 
			datepart(week, 日期字段)
	end as date_week	
	

日期是周几 dayname(date) 和 dayofweek(date)

mysql> select dayname(‘2020-07-16‘);
+-----------------------+
| dayname(‘2020-07-16‘) |
+-----------------------+
| Thursday              |
+-----------------------+
1 row in set (0.00 sec)

mysql> select dayofweek(‘2020-07-16‘);
+-------------------------+
| dayofweek(‘2020-07-16‘) |
+-------------------------+
|                       5 |
+-------------------------+
1 row in set (0.00 sec)

这个返回天还是有点问题, 中国人看应该返回 4 才对, 它又是从 周天开始算的, 我有点懵逼...

**日期是一月 or 年的第多少天 dayofmonth(); dayofyear(); **

mysql> select dayofmonth(‘2020/7/16‘);
+-------------------------+
| dayofmonth(‘2020/7/16‘) |
+-------------------------+
|                      16 |
+-------------------------+
1 row in set (0.00 sec)

mysql> select dayofyear(‘2020-7-16‘);
+------------------------+
| dayofyear(‘2020-7-16‘) |
+------------------------+
|                    198 |
+------------------------+
1 row in set (0.00 sec)

计算两个日期的差 datediff ( )

  • datediff (data_01, date_02) 返回 date_01 - date_02 相差的天数
mysql> select datediff(‘2020-7-16‘, ‘2020-07-01‘);
+-------------------------------------+
| datediff(‘2020-7-16‘, ‘2020-07-01‘) |
+-------------------------------------+
|                                  15 |
+-------------------------------------+
1 row in set (0.00 sec)

mysql> select datediff(‘2020-7-16‘, ‘2020-07-20‘);
+-------------------------------------+
| datediff(‘2020-7-16‘, ‘2020-07-20‘) |
+-------------------------------------+
|                                  -4 |
+-------------------------------------+
1 row in set (0.00 sec)

mysql> select datediff(‘2020-7-16‘, ‘2020-01-1‘);
+------------------------------------+
| datediff(‘2020-7-16‘, ‘2020-01-1‘) |
+------------------------------------+
|                                197 |
+------------------------------------+
1 row in set (0.00 sec)

计算日期当月的最后一天 last_day(date)

mysql> select last_day(‘2020-07-16‘);
+------------------------+
| last_day(‘2020-07-16‘) |
+------------------------+
| 2020-07-31             |
+------------------------+
1 row in set (0.00 sec)

mysql> select last_day(now());
+-----------------+
| last_day(now()) |
+-----------------+
| 2020-07-31      |
+-----------------+
1 row in set (0.00 sec)

mysql> select last_day(‘2020-2-1‘);
+----------------------+
| last_day(‘2020-2-1‘) |
+----------------------+
| 2020-02-29           |
+----------------------+
1 row in set (0.00 sec)

以上是关于MySQL实现常用分析函数的主要内容,如果未能解决你的问题,请参考以下文章

Mysql 常用时间函数(上)

直观理解:MySQL常用窗口函数

MySQL中的GIS几何函数和空间分析函数

集合的常用线程安全实现类使用及源码分析

集合的常用线程安全实现类使用及源码分析

分享|R语言数据挖掘分析常用包和函数