前言
作为后端开发的我们,在日常工作中,经常会接到客户、运营或者产品经理提的一些临时需求。
比如:给你一个订单号,查询有哪些商品有问题,或者提供提出这样一个需求,按某种格式导出某些表某些字段的数据。
为了快速解决线上问题,或者满足他们提出的这些临时需求,我们经常需要写一些SQL脚本,来实现这些需求。
当然临时需求太多了,我没办法一一列举,这篇文章的重点是更大家一起聊聊:
- 如何将多行数据转换成一行。
- 如何将一行数据转换成多行。
这两个需求是日常工作中经常会遇到,希望这篇文章对你会有所帮助。
1 将多行转换成一行
假如现在有一张用户表,有这些数据:
产品有一个需求,想要找出年龄等于23岁的用户id,拼接成一个字符串给他。
过滤产品想要的数据非常容易,用下面这条sql就能轻松实现:
select id from user where age=23;但该SQL的执行结果是下面这样的:
获取到的用户id,返回了多行数据。
怎么才能变成一行数据呢?
答:这就可以使用MySQL自带的group_concat()函数了。
将SQL语句改造这样的:
select group_concat(id) from user where age=23;执行结果:
只返回了一条数据,多个用户id用逗号分割,拼接成了一个字符串。
这样就可以实现多行转一行了。
2 将一行转换成多行
有时候,我们需要将一行转成多行。
假如有这样一种场景。
有一张产品表,里面的数据是这样的:

还有一张订单表,里面的数据是这样的:
其中订单表中有个字段product_id,其实是一个varchar类型,保存的是多个产品id用逗号拼接而成的数据。
现在客户有这样一个需求,要导出表中的订单和商品信息,返回的字段有:订单id,订单code,订单name,商品id,商品name和商品model。
这个需求乍一看,很简单。
只需要将订单表和商品表,这两张表join,起来不就完成任务了?
确实要怎么做,但是两张表join时,跟在on关键字后面的条件是什么呢?
用等于号吗?
select s1.id,s1.code,s1.name,s2.id,s2.name,s2.model
from`order`s1
inner join product s2
on s1.product_id=s2.id显然不对,只返回了测试商品1的数据,其他的商品都没有返回。
用in关键字?
select s1.id,s1.code,s1.name,s2.id,s2.name,s2.model
from `order`s1
inner join products2
on s2.id in (s1.product_id)也不对。
跟刚刚的返回结果是一样的。
s2.id是数字类型的,而s1.product_id是字符串类型的,会不会是二者类型不一致,导致查出的数据问题?
使用concat函数将s2.id转换成了字符串类型:
select s1.id,s1.code,s1.name,s2.id,s2.name,s2.model
from `order`s1
inner join product s2
on concat(s2.id,'') in (s1.product_id)执行结果就更不对了,连数据都没返回。
使用split函数分割s1.product_id字段中的字符串,变成多个值?
很不幸的是在MySQL5.7是不支持split这个函数的。
有没有其他的解决办法呢?
答:使用find_in_set()函数。
将上面的sql调整一下:
select s1.id,s1.code,s1.name,s2.id,s2.name,s2.model
from `order`s1
inner join product s2
on (find_in_set(s2.id,s1.product_id)<>0)执行结果:
执行了客户的需求,将一行数据转换成了多行数据。