MySQL/MariaDB如何实现数据透视表

数据透视表(Pivot Table)是 Excel 中一个非常实用的分析功能,可以用于实现复杂的数据分类汇总和对比分析,是数据分析师和运营人员必备技能之一。今天我们来谈谈如何在 MySQL/MariaDB 中如何实现相同的功能。使用 CASE 表达式和分组聚合
数据透视表的本质就是按照行和列的不同组合进行数据分组,然后对结果进行汇总;因此,它和数据库中的分组(GROUP BY)加聚合函数(COUNT、SUM、AVG 等)的功能非常类似。
我们首先使用以下 GROUP BY 子句对销售数据进行分类汇总:select coalesce(product, ‘【全部产品】’) “产品”, coalesce(channel, ‘【所有渠道】’) “渠道”, any_value(coalesce(extract(year_month from saledate), ‘【所有月份】’)) “月份”, sum(amount) "销量"from sales_datagroup by product,channel,extract(year_month from saledate) with rollup;以上语句按照产品、渠道以及月份进行汇总;with rollup 选项用于生成不同层次的小计、合计以及总计;coalesce 函数用于将汇总行中的 NULL 值显示为相应的信息;any_value 函数用于返回分组内的任意数据,如果去掉会返回语法错误(MySQL 的一个 bug)。该查询返回的结果如下:产品 |渠道 |月份 |销量 |---------|---------|-----------|-------|桔子 |京东 |201901 | 41289|桔子 |京东 |201902 | 43913|桔子 |京东 |201903 | 49803|桔子 |京东 |201904 | 49256|桔子 |京东 |201905 | 64889|桔子 |京东 |201906 | 62649|桔子 |京东 |【所有月份】| 311799|桔子 |店面 |201901 | 41306|桔子 |店面 |201902 | 37906|桔子 |店面 |201903 | 48866|桔子 |店面 |201904 | 48673|桔子 |店面 |201905 | 58998|桔子 |店面 |201906 | 58931|桔子 |店面 |【所有月份】| 294680|桔子 |淘宝 |201901 | 43488|桔子 |淘宝 |201902 | 37598|桔子 |淘宝 |201903 | 48621|桔子 |淘宝 |201904 | 49919|桔子 |淘宝 |201905 | 58530|桔子 |淘宝 |201906 | 64626|桔子 |淘宝 |【所有月份】| 302782|桔子 |【所有渠道】|【所有月份】| 909261|…香蕉 |【所有渠道】|【所有月份】| 925369|【全部产品】|【所有渠道】|【所有月份】|2771682|实际上,我们已经得到了销量的汇总结果,只不过需要将数据按照不同月份显示为不同的列;也就是需要将行转换为列,这个功能可以使用 CASE 表达式实现:select coalesce(product, ‘【全部产品】’) “产品”, coalesce(channel, ‘【所有渠道】’) “渠道”, sum(case extract(year_month from saledate) when 201901 then amount else 0 end) “一月”, sum(case extract(year_month from saledate) when 201902 then amount else 0 end) “二月”, sum(case extract(year_month from saledate) when 201903 then amount else 0 end) “三月”, sum(case extract(year_month from saledate) when 201904 then amount else 0 end) “四月”, sum(case extract(year_month from saledate) when 201905 then amount else 0 end) “五月”, sum(case extract(year_month from saledate) when 201906 then amount else 0 end) “六月”, sum(amount) “总计"from sales_datagroup by product, channel with rollup;第一个 SUM 函数中的 CASE 表达式只汇总 201901 月份的销量,其他月份销量设置为 0;后面的 SUM 函数依次类推,得到了每个月的销量汇总和所有月份的总计。该查询返回的数据透视表如下:产品 |渠道 |一月 |二月 |三月 |四月 |五月 |六月 |总计 |----------|----------|------|------|------|------|------|------|-------|桔子 |京东 | 41289| 43913| 49803| 49256| 64889| 62649| 311799|桔子 |店面 | 41306| 37906| 48866| 48673| 58998| 58931| 294680|桔子 |淘宝 | 43488| 37598| 48621| 49919| 58530| 64626| 302782|桔子 |【所有渠道】|126083|119417|147290|147848|182417|186206| 909261|苹果 |京东 | 38269| 40593| 56552| 56662| 64493| 62045| 318614|苹果 |店面 | 43845| 40539| 44909| 55646| 56771| 64933| 306643|苹果 |淘宝 | 42969| 43289| 48769| 58052| 58872| 59844| 311795|苹果 |【所有渠道】|125083|124421|150230|170360|180136|186822| 937052|香蕉 |京东 | 36879| 36981| 51748| 54801| 64936| 60688| 306033|香蕉 |店面 | 41210| 39420| 50884| 52085| 60249| 67597| 311445|香蕉 |淘宝 | 42468| 41955| 52780| 54971| 56504| 59213| 307891|香蕉 |【所有渠道】|120557|118356|155412|161857|181689|187498| 925369|【全部产品】|【所有渠道】|371723|362194|452932|480065|544242|560526|2771682|📝MySQL 中的 IF(expr1,expr2,expr3) 函数也可以用于替换上面 CASE 表达式。有行转列就有列转行,MySQL 也没有专门的函数处理这种情况,可以使用 UNION 操作符将多个结果集进行合并。例如:with d as ( select product, channel, sum(case extract(year_month from saledate) when 201901 then amount else 0 end) s01, sum(case extract(year_month from saledate) when 201902 then amount else 0 end) s02, sum(case extract(year_month from saledate) when 201903 then amount else 0 end) s03, sum(case extract(year_month from saledate) when 201904 then amount else 0 end) s04, sum(case extract(year_month from saledate) when 201905 then amount else 0 end) s05, sum(case extract(year_month from saledate) when 201906 then amount else 0 end) s06 from sales_data group by product, channel)select product, channel, 201901 saledate, s01 amount from dunion allselect product, channel, 201902 saledate, s02 from dunion allselect product, channel, 201903 saledate, s03 from dunion allselect product, channel, 201904 saledate, s04 from dunion allselect product, channel, 201905 saledate, s05 from dunion allselect product, channel, 201906 saledate, s06 from d;通用表表达(with 子句)构造了包含多个月份的销量数据,每个月份都是一列;然后每个查询返回一个月份的数据,并且通过 union all 操作符将所有结果合并到一起。
使用预编译的动态 SQL 语句
使用 CASE 表达式和聚合函数实现数据透视表的方法存在一定的局限性,假如还有 7 月份到 12 月份的销量需要统计,我们就需要修改查询语句增加这部分的处理。为此,我们可以使用动态 SQL 自动生成行列转换的语句:select group_concat( distinct concat( ’ sum(case extract(year_month from saledate) when ‘, dt, ’ then amount else 0 end) as "’, dt, '”‘) ) into @sqlfrom ( select extract(year_month from saledate) as dt from sales_data order by saledate) d;
set @sql = concat(‘select coalesce(product, ‘’【全部产品】’’) “产品”, coalesce(channel, ‘’【所有渠道】‘’) “渠道”,‘, @sql, ‘, sum(amount) “总计” from sales_data group by product, channel with rollup;’);select @sql;prepare stmt from @sql;execute stmt;deallocate prepare stmt;首先,通过查询 sales_data 表找出所有的月份并且构造 sum 函数,将构造的语句存入变量 @sql 中;group_concat 函数可以将多行字符串合并成单个字符串。📝group_concat 函数允许返回的最大长度(字节)由系统变量 group_concat_max_len 进行设置,默认值为 1024。然后,使用 set 命令将查询语句的其他部分和已有的内容进行合并,生成的查询语句如下:select coalesce(product, ‘【全部产品】’) “产品”, coalesce(channel, ‘【所有渠道】’) “渠道”, sum(case extract(year_month from saledate) when 201901 then amount else 0 end) as “201901”, sum(case extract(year_month from saledate) when 201902 then amount else 0 end) as “201902”, sum(case extract(year_month from saledate) when 201903 then amount else 0 end) as “201903”, sum(case extract(year_month from saledate) when 201904 then amount else 0 end) as “201904”, sum(case extract(year_month from saledate) when 201905 then amount else 0 end) as “201905”, sum(case extract(year_month from saledate) when 201906 then amount else 0 end) as “201906”, sum(amount) "总计"from sales_datagroup by product, channel with rollup;最后通过预编译命令执行该语句并返回结果,即使增加了其他月份的销售数据也不需要手动修改查询语句。
使用 CONNECT 存储引擎
如果使用 MariaDB 10.0 以上的版本,可以利用 CONNECT 存储引擎中的 PIVOT 表类型实现数据透视表。
首先,我们需要安装 CONNECT 存储引擎。Windows 系统可以执行以下命令进行动态安装:INSTALL SONAME ‘ha_connect’;也可以在配置文件 my.ini 中增加以下内容,不过需要重启服务:[mysqld]plugin_load_add = ha_connect📝对于 Linux 操作系统,CONNECT 存储引擎的安装过程可以参考官方文档。接下来我们定义一个 pivot 类型的表:create table pivot_sales( product varchar(20) not null, channel varchar(20) not null, 201901 decimal(10,2) not null flag=1, 201902 decimal(10,2) not null flag=1, 201903 decimal(10,2) not null flag=1, 201904 decimal(10,2) not null flag=1, 201905 decimal(10,2) not null flag=1, 201906 decimal(10,2) not null flag=1)engine=connect table_type=pivotoption_list=‘PivotCol=saledate,FncCol=amount,host=127.0.0.1,user=root, password=p123456,port=3306’SrcDef=‘select product,channel,date_format(saledate, ‘’%Y%m’’) saledate,sum(amount) amount from sales_data group by product,channel,date_format(saledate, ‘’%Y%m’‘)’;其中,engine 定义存储引擎为 connect;table_type 定义表的类型为 pivot;option_list 用于定义各种选项,PivotCol 表示要转换成多个字段的数据所在的列,FncCol 指定要进行汇总的字段,其他是连接源表服务器的信息;SrcDef 用于指定源表查询语句,也可以使用 Tabname 指定表名;上面的字段是透视表的结构,flag=1 表示聚合之后的字段。
创建成功之后,我们就可以直接查询 pivot_sales 表中的数据了:select * from pivot_sales;

product |channel |201901 |201902 |201903 |201904 |201905 |201906 |--------|---------|--------|--------|--------|--------|--------|--------|桔子 |京东 |41289.00|43913.00|49803.00|49256.00|64889.00|62649.00|桔子 |店面 |41306.00|37906.00|48866.00|48673.00|58998.00|58931.00|桔子 |淘宝 |43488.00|37598.00|48621.00|49919.00|58530.00|64626.00|苹果 |京东 |38269.00|40593.00|56552.00|56662.00|64493.00|62045.00|苹果 |店面 |43845.00|40539.00|44909.00|55646.00|56771.00|64933.00|苹果 |淘宝 |42969.00|43289.00|48769.00|58052.00|58872.00|59844.00|香蕉 |京东 |36879.00|36981.00|51748.00|54801.00|64936.00|60688.00|香蕉 |店面 |41210.00|39420.00|50884.00|52085.00|60249.00|67597.00|香蕉 |淘宝 |42468.00|41955.00|52780.00|54971.00|56504.00|59213.00|目前,PIVOT 表支持的功能有限,只能进行一些基本的操作。例如:-- 不会出错select * from pivot_saleswhere channel =‘京东’;

– 语法错误select channel from pivot_saleswhere channel =‘京东’;
如果觉得文章对你有用,欢迎评论📝、点赞👍、推荐🎁

var first_sceen__time = (+new Date());
if (“” == 1 && document.getElementById(‘js_content’)) {
document.getElementById(‘js_content’).addEventListener(“selectstart”,function(e){ e.preventDefault(); });
}

阅读
425

28

3

写留言

SQL编程思想关注 10293已同步到看一看 写下你的评论 写留言 关闭0个朋友更多

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/887911.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

迁移学习案例-python代码

大白话 迁移学习就是用不太相同但又有一些联系的A和B数据,训练同一个网络。比如,先用A数据训练一下网络,然后再用B数据训练一下网络,那么就说最后的模型是从A迁移到B的。 迁移学习的具体形式是多种多样的,比如先用A训练…

LeetCode讲解篇之300. 最长递增子序列

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 这题我们可以通过动态规划求解&#xff0c;使用一个数组f&#xff0c;数组f的i号元素表示[0, i]范围内最长递增子序列的长度 状态转移方程&#xff1a;f[i] max(f[j] 1)&#xff0c;其中 0 < j < i 题…

docker快速安装ELK

一、创建elk目录 创建/elk/elasticsearch/data/目录 mkdir -p /usr/local/share/elk/elasticsearch/data/ 创建/elk/logstash/pipeline/目录 mkdir -p /usr/local/share/elk/logstash/pipeline/ 创建/elk/kibana/conf/目录 mkdir -p /usr/local/share/elk/kibana/conf/ 二、创建…

大模型应用新领域:探寻终端侧 AI 竞争核心|智于终端

2024年过去2/3&#xff0c;大模型领域的一个共识开始愈加清晰&#xff1a; AI技术的真正价值在于其普惠性。没有应用&#xff0c;基础模型将无法发挥其价值。 于是乎&#xff0c;回顾这大半年&#xff0c;从互联网大厂到手机厂商&#xff0c;各路人马都在探索AI时代Killer AP…

【超级详细解释】力扣每日一题 134.加油站 48. 旋转图像

134.加油站 力扣 这是一个很好的问题。这个思路其实基于一种贪心策略。我们从整个路径的油量变化来理解它&#xff0c;结合一个直观的“最低点法则”&#xff0c;来确保找到正确的起点。 问题的核心&#xff1a;油量差值的累积 对于每个加油站&#xff0c;我们有两个数组&…

1、如何查看电脑已经连接上的wifi的密码?

在电脑桌面右下角的如下位置&#xff1a;双击打开查看当前连接上的wifi的名字&#xff1a;ZTE-kfdGYX-5G 按一下键盘上的win R 键, 输入【cmd】 然后&#xff0c;按一下【回车】。 输入netsh wlan show profile ”wifi名称” keyclear : 输入完成后&#xff0c;按一下回车&…

51单片机的水质检测系统【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块温度传感器ph传感器浑浊度传感器蓝牙继电器LED、按键和蜂鸣器等模块构成。适用于水质监测系统&#xff0c;含检测和调整水温、浑浊度、ph等相似项目。 可实现功能: 1、LCD1602实时显示水温、水体ph和浑浊度 2、温…

Studying-多线程学习Part3 - condition_variable与其使用场景、C++11实现跨平台线程池

来源&#xff1a;多线程学习 目录 condition_variable与其使用场景 生产者与消费者模型 C11实现跨平台线程池 condition_variable与其使用场景 生产者与消费者模型 生产者-消费者模式是一种经典的多线程设计模式&#xff0c;用于解决多个线程之间的数据共享和协作问题。…

基于PHP的校园二手书交易管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的校园二手书交易管理系统 一 介绍 此二手书交易管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈&#xff1a;phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注…

k8s中pod的管理

一、资源管理 1.概述 说到k8s中的pod&#xff0c;即荚的意思&#xff0c;就不得不先提到k8s中的资源管理&#xff0c;k8s中可以用以下命令查看我们的资源&#xff1a; kubectl api-resources 比如我们现在需要使用k8s开启一个东西&#xff0c;那么k8s通过apiserver去对比etc…

《从零开始大模型开发与微调》真的把大模型说透了!零基础入门一定要看!

2022年底&#xff0c;ChatGPT震撼上线&#xff0c;大语言模型技术迅速“席卷”了整个社会&#xff0c;人工智能技术因此迎来了一次重要进展。与大语言模型相关的研发岗薪资更是水涨船高&#xff0c;基本都是5w月薪起。很多程序员也想跟上ChatGPT脚步&#xff0c;今天给大家带来…

51单片机系列-串口(UART)通信技术

&#x1f308;个人主页&#xff1a; 羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 并行通信和串行通信 并行方式 并行方式&#xff1a;数据的各位用多条数据线同时发送或者同时接收 并行通信特点&#xff1a;传送速度快&#xff0c;但因需要多根传输线&#xf…

免杀对抗—GOC#反VT沙盒资源分离混淆加密

前言 今天的主要内容是反VT沙盒&#xff0c;我们都知道生成的后门会被杀软上穿到沙盒中去运行&#xff0c;去逆向。如此一来我们的后门就很容易被查杀掉&#xff0c;但如果我们对后门进行一些操作&#xff0c;让它在被逆向的时候&#xff0c;反编译出一堆乱码&#xff0c;或者…

【大语言模型-论文精读】用于医疗领域摘要任务的大型语言模型评估综述

【大语言模型-论文精读】用于医疗领域摘要任务的大型语言模型评估综述 论文信息&#xff1a; 用于医疗领域摘要任务的大型语言模型评估&#xff1a;一篇叙述性综述&#xff0c; 文章是由 Emma Croxford , Yanjun Gao 博士 , Nicholas Pellegrino , Karen K. Wong 等人近期合作…

STM32PWM应用

目录 一、输出比较(OC) 二、PWM&#xff1a; 1、简介 2、基本结构 3、参数计算 三、PWM驱动LED呼吸灯 1、代码 四、PWM驱动Sg90舵机 1、工作原理 2、完整代码 五、PWM驱动直流电机 1、TB6612芯片模块 2、完整代码&#xff1a; 一、输出比较(OC) OC&#xff08;Outp…

智能医疗:Spring Boot医院管理系统开发

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常适…

【Python】PDFMiner.six:高效处理PDF文档的Python工具

PDF是一种广泛使用的文件格式&#xff0c;特别适用于呈现固定布局的文档。然而&#xff0c;提取PDF文件中的文本和信息并不总是那么简单。幸好有许多Python库可以帮助我们&#xff0c;其中&#xff0c;PDFMiner.six 是一个功能强大、专门用于PDF文档解析的库。 ⭕️宇宙起点 &a…

cnn突破四(生成卷积核与固定核对比)

cnn突破三中生成四个卷积核&#xff0c;训练6万次&#xff0c;91分&#xff0c;再训练6万次&#xff0c;95分&#xff0c;不是很满意&#xff0c;但又找不到问题点&#xff0c;所以就想了个办法&#xff0c;使用三个固定核&#xff0c;加上三层bpnet神经网络&#xff0c;看看效…

王道-数据结构

1 设数组data[m]作为循环队列的存储空间,front为队头指针,rear为队尾指针,则执行出队操作后其头指针front值为____ 答案:D 解析:队列的头指针指向队首元素的实际位置,因此出队操作后,头指针需向上移动一个元素的位置。循环队列的容量为m,所以头指针front加1以后,需…

【d60】【Java】【力扣】509. 斐波那契数

思路 要做的问题&#xff1a;求F&#xff08;n&#xff09;, F&#xff08;n&#xff09;就等于F(n-1)F(n-2)&#xff0c;要把这个F(n-1)F(n-2)当作常量&#xff0c;已经得到的值&#xff0c; 结束条件&#xff1a;如果是第1 第2 个数字的时候&#xff0c;没有n-1和n-2,所以…