ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

SQL将字符串分裂成多行

2021-08-05 01:31:26  阅读:255  来源: 互联网

标签:多行 INDEX SQL 字符串 2014 2011 2010 2013 2012


SQL将字符串分裂成多行

最近遇到一个需求,我有一个表user,里面有两条记录

同时也有一个order表,里面有4条记录

然后我需要查每个用户2010、2011、2012、2013、2014这五年的购物记录,如果有记录,就显示,如果没有记录,就字段留空。

就像下面这种结果:

但是倘若我正常联表查询:

SELECT
	* 
FROM
	USER u
	LEFT JOIN order1 o ON u.id = o.user_id 
WHERE
	YEAR IN ( '2010', '2011', '2012', '2013', '2014' )

那最终也只会是下面这种效果,没有值的2014年就没有记录了。

为了实现我想要的效果,那我就必须给用户表每条记录,都加上一个年份,已达到下面的效果

而要实现这样的效果,可以考虑笛卡尔积,但是笛卡尔积也只能是表跟表进行,我传入的年份也只是字符串或者数组。我需要一个表,而且还是临时表,来实现笛卡尔积:

select 
	* 
from 
	user , years

所以这个问题就转变成如何将一个数组,或者一个字符串分离成多行的问题了。

针对MySQL:

SELECT
	SUBSTRING_INDEX( SUBSTRING_INDEX( '2010,2011,2012,2013,2014', ',', help_topic_id + 1 ), ',',- 1 ) AS num 
FROM
	mysql.help_topic 
WHERE
	help_topic_id < LENGTH( '2010,2011,2012,2013,2014' )- LENGTH(REPLACE ( '2010,2011,2012,2013,2014', ',', '' ))+ 1 

分析下这个SQL:

SUBSTRING_INDEX:切割字符串函数,返回第几个分隔符前面的字符串。

​ 第一个参数:目标字符串

​ 第二个参数:分割符

​ 第三个参数:第几个分隔符,从1开始。如果是负数,则分隔符从右往左数,并且返回分隔符后面的字符串

-- 例如:
SUBSTRING_INDEX( '2010,2011,2012,2013,2014', ',',  1 )   返回 2010
SUBSTRING_INDEX( '2010,2011,2012,2013,2014', ',',  2 )   返回 2010,2011
SUBSTRING_INDEX( '2010,2011,2012,2013,2014', ',',  3 )   返回 2010,2011,2012
SUBSTRING_INDEX( '2010,2011,2012,2013,2014', ',',  30 )   返回 2010,2011,2012,2013,2014

SUBSTRING_INDEX( '2010,2011,2012,2013,2014', ',',  -1 )   返回 2014
SUBSTRING_INDEX( '2010,2011,2012,2013,2014', ',',  -2 )   返回 2013,2014
SUBSTRING_INDEX( '2010,2011,2012,2013,2014', ',',  -3 )   返回 2012,2013,2014
SUBSTRING_INDEX( '2010,2011,2012,2013,2014', ',',  -30 )   返回 2010,2011,2012,2013,2014

-- 想必到这里,前面用两重SUBSTRING_INDEX,你们也知道是为啥了把

help_topic:这个表是mysql数据库里面的内置表,有什么用咱不需要管,咱先看下他里面有啥:

咱也不知道这玩意干啥的,但是看回我们的SQL,我们发现我们有且仅有用到这个表的help_topic_id字段,是不是突然觉得很懵,为啥要用这个字段呢?

我们再回头看下刚刚咱们分析的那个SUBSTRING_INDEX函数,他第三个参数是不是需要一个数字,从1开始,一直递增。

所以我们用这个表,仅仅是因为它id字段从0开始,而且不断递增,刚好符合我们函数的需要,而我们查这个表,他的记录就是从id为0开始。

如果你不想用这个help_topic表,或者你没有权限,你完全可以自己创建一个递增的表,插入一些记录,不需要很多字段,只要有个递增字段就OK了。

LENGTH:返回字符串的长度。

​ 第一个参数:字符串

REPLACE:替换字符串中指定的字串

​ 第一个参数:原字符串

​ 第二个参数:要替换的旧串

​ 第三个参数:要替换的新串

LENGTH( '2010,2011,2012,2013,2014' ) - LENGTH(REPLACE ( '2010,2011,2012,2013,2014', ',', '' ))+ 1 
这里你们可能会不太理解,其实简化下:
LENGTH( '2010,2011,2012,2013,2014' ) - LENGTH( '20102011201220132014')+ 1 
现在再看,缺了啥?   缺了分隔符。  两个长度一减,在加个1,那不就是元素的个数么

现在再看回这个SQL:

SELECT
	SUBSTRING_INDEX( SUBSTRING_INDEX( '2010,2011,2012,2013,2014', ',', help_topic_id + 1 ), ',',- 1 ) AS num  -- 两次切割字符串,获取元素
FROM
	mysql.help_topic 		-- 借用一个递增字段
WHERE
	help_topic_id < LENGTH( '2010,2011,2012,2013,2014' )- LENGTH(REPLACE ( '2010,2011,2012,2013,2014', ',', '' ))+ 1 -- 确定元素个数

针对postgresql:

postgresql要分离多行其实很简单

	SELECT unnest(string_to_array('2010,2011,2012,2013,2014', ',')) AS year  

unnest:unnest 函数将输入的数组转换成一个表,这个表的每一列都代表相应的一个数组中的元素。如果unnest与其他字段一起出现在select中,就相当于其他字段进行了一次join。

string_to_array:将字符串切割成数组

​ 第一个参数:字符串

​ 第二个参数:分隔符

​ 第三个参数:指定元素用null替换

函数可以参考这个文章:https://blog.csdn.net/rocklee/article/details/79398903

针对oracle:

SELECT
	regexp_substr( '2019,2020,2015,2018', '[^,]+', 1, LEVEL ) year 
FROM
	dual  connect by  LEVEL <= regexp_count ( '2019,2020,2015,2018', ',' ) + 1

regexp_substr:按正则表达式切割字符串
第一个参数:需要进行正则处理的字符串
第二个参数:进行匹配的正则表达式
第三个参数:起始位置,从字符串的第几个字符开始正则表达式匹配(默认为1) 注意:字符串最初的位置是1而不是0
第四个参数:获取第几个分割出来的组(分割后最初的字符串会按分割的顺序排列成组)
第五个参数:模式(‘i’不区分大小写进行检索;‘c’区分大小写进行检索。默认为’c’)针对的是正则表达式里字符大小写的匹配

'[^,]+' 这是个正则表达式,^是匹配开始标志,但是 ^ 在括号中,他就是“非”,而 ^, 那就是匹配除了逗号外的东西。[ ] 中括号,是一个可选内容的范围,例如[1, 2, 3, a],那就是只匹配1、2、3、a这四个字符。+ 表示至少1个。

image

connect by :咱先来看看基本语法

select *,level from table [start with condition1] connect by [prior] id = parentid
select *,level from table [start with condition1] connect by id = [prior] parentid

一般用来查找存在父子关系的数据,也就是树形结构的数据;其返还的数据也能够明确的区分出每一层的数据。

start with condition1 是用来限制第一层的数据,或者叫根节点数据;以这部分数据为基础来查找第二层数据,然后以第二层数据查找第三层数据以此类推。

connect by [prior] id=parentid 这部分是用来指明oracle在查找数据时以怎样的一种关系去查找;比如说查找第二层的数据时用第一层数据的id去跟表里面记录的parentid字段进行匹配,如果这个条件成立那么查找出来的数据就是第二层数据,同理查找第三层第四层…等等都是按这样去匹配。

简单来说:
select * from table 把全部数据都查出来
start with condition1  根据条件筛选第一层的记录
connect by 下一层的记录需要满足什么条件
prior  这个关键字修饰的字段就是上一层的字段
level  层级,从1开始
SELECT
	regexp_substr( '2019,2020,2015,2018', '[^,]+', 1, LEVEL ) year 	-- 正则表达式切割成数组,再根据level从1开始获取元素
FROM
	dual  
connect by  LEVEL <= regexp_count ( '2019,2020,2015,2018', ',' ) + 1   -- 每一层都会去判断记录是否满足条件,当level到了元素个数后,就不在递归了

标签:多行,INDEX,SQL,字符串,2014,2011,2010,2013,2012
来源: https://www.cnblogs.com/chongcheng/p/15101462.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有