SQL-一道特殊的字符串分解题目
本题不是一道直接的字符串拆解,
应用场景如下,表中有一个字段,是表示事件受影响的国家集合,使用逗号进行分隔,不幸的是,居然发现有些国家本身就带有逗号,这样在规范化的时候,如何准确地找到这些国家呢?
以下的代码是有一定限制的。但基本上够用。
下面的代码使用到了分析函数lag和lead还有cte,sqlserver2012及其以后的版本都支持,oracle好像10g以上就支持了。
主要思路:
字符串的分解,可以使用数字辅助表,然后cross join刷副本,然后根本分隔符出现的位置然后切豁字符串拆解到我们需要的东东。(解决方案中我使用的递归CTE来处理找到对应的位置)
现在还需要多加一步,就是对拆解的部分进行验证和去重不符合要求的那一部。
使用LAG和LEAD的好处,就是不需要再用自连接去找到对应的下一条数据了。
本题的解题原则是如何长项能连接到正确的国家,则取长项的,否则取短项的。
代码如下:
--准备示例表与数据 drop table my_countries; drop table valid_country; create table my_countries(rid int,country_name_cc varchar(200)); insert into my_countries(rid,country_name_cc) values(1,'china,test, public of'); insert into my_countries(rid,country_name_cc) values(2,'us, public of,china,Evan, public of'); create table valid_country(cid int, country_name varchar(30)); insert into valid_country(cid,country_name) values(1,'china'); insert into valid_country(cid,country_name) values(2,'test, public of'); insert into valid_country(cid,country_name) values(3,'Evan, public of'); insert into valid_country(cid,country_name) values(4,'us, public of'); insert into valid_country(cid,country_name) values(5,'Evan'); --select * from my_countries; --select * from valid_country;
正确的结果是:

WITH SPLIT_COUNTRY AS
(
SELECT
RID,
1 AS LVL,
1 AS STARTPOS,
CHARINDEX(',',COUNTRY_NAME_CC+',')-1 AS ENDPOS
FROM MY_COUNTRIES
UNION ALL
SELECT
SC.RID,
LVL+1 AS LVL,
ENDPOS+2,
CHARINDEX(',',COUNTRY_NAME_CC+',',ENDPOS+2)-1
FROM
MY_COUNTRIES CC JOIN
SPLIT_COUNTRY SC ON CC.RID=SC.RID
WHERE CHARINDEX(',',CC.COUNTRY_NAME_CC+',',ENDPOS+2)>0
)
,CTE_COUNTRY AS (
SELECT RID,LVL,STARTPOS,ENDPOS,LEAD(ENDPOS,1) OVER(PARTITION BY RID ORDER BY LVL) AS NEXTENDPOS FROM SPLIT_COUNTRY
)
,CTE AS (
SELECT MC.RID,SC.LVL,
CASE WHEN NEXTENDPOS IS NOT NULL AND EXISTS (SELECT * FROM VALID_COUNTRY VC WHERE VC.COUNTRY_NAME = SUBSTRING(COUNTRY_NAME_CC,STARTPOS,NEXTENDPOS-STARTPOS+1)) THEN
SUBSTRING(COUNTRY_NAME_CC,STARTPOS,NEXTENDPOS-STARTPOS+1)
ELSE
SUBSTRING(MC.COUNTRY_NAME_CC,STARTPOS,ENDPOS-STARTPOS+1)
END
AS COUNTRY
FROM MY_COUNTRIES MC JOIN CTE_COUNTRY SC
ON MC.RID=SC.RID
)
,CHECK_VALID AS (
SELECT CASE WHEN CHARINDEX(',',LAG(COUNTRY,1) OVER(PARTITION BY RID ORDER BY LVL))>0 THEN 0 ELSE 1 END AS ISVALID,
* FROM CTE
)
SELECT CV.RID,CV.COUNTRY,VC.CID FROM CHECK_VALID CV JOIN VALID_COUNTRY VC
ON CV.COUNTRY = VC.COUNTRY_NAME
AND ISVALID=1 ORDER BY RID;
另一种方案,在第一种的基础上稍加修改:
WITH SPLIT_COUNTRY AS
(
SELECT
RID,
1 AS LVL,
1 AS STARTPOS,
CHARINDEX(',',COUNTRY_NAME_CC+',')-1 AS ENDPOS
FROM MY_COUNTRIES
UNION ALL
SELECT
SC.RID,
LVL+1 AS LVL,
ENDPOS+2,
CHARINDEX(',',COUNTRY_NAME_CC+',',ENDPOS+2)-1
FROM
MY_COUNTRIES CC JOIN
SPLIT_COUNTRY SC ON CC.RID=SC.RID
WHERE CHARINDEX(',',CC.COUNTRY_NAME_CC+',',ENDPOS+2)>0
)
,CTE_COUNTRY AS (
SELECT RID,LVL,STARTPOS,ENDPOS,LEAD(ENDPOS,1) OVER(PARTITION BY RID ORDER BY LVL) AS NEXTENDPOS FROM SPLIT_COUNTRY
)
,CTE AS (
SELECT MC.RID,SC.LVL,
SUBSTRING(MC.COUNTRY_NAME_CC,STARTPOS,ENDPOS-STARTPOS+1) AS COUNTRY,
SUBSTRING(COUNTRY_NAME_CC,STARTPOS,NEXTENDPOS-STARTPOS+1) AS COUNTRY2
FROM MY_COUNTRIES MC JOIN CTE_COUNTRY SC
ON MC.RID=SC.RID
)
SELECT CTE.RID,VC.COUNTRY_NAME,VC.CID
FROM
CTE JOIN VALID_COUNTRY VC
ON (CASE WHEN EXISTS(SELECT * FROM VALID_COUNTRY X WHERE X.COUNTRY_NAME=CTE.COUNTRY2) THEN CTE.COUNTRY2
ELSE CTE.COUNTRY END) = VC.COUNTRY_NAME
;
SQL-一道特殊的字符串分解题目的更多相关文章
- SQL Server中截取字符串常用函数
SQL Server 中截取字符串常用的函数: .LEFT ( character_expression , integer_expression ) 函数说明:LEFT ( '源字符串' , '要截 ...
- 使用List把一个长字符串分解成若干个短字符串
把一个长字符串分解成若干个固定长度的短字符串,由于事先不知道长字符串的长度,以及短字符串的数量,只能使用List. public static void get_list_sbody(String s ...
- sql server 查找包含字符串的对象
sql server 查找包含字符串的对象 SELECT sm.object_id, OBJECT_NAME(sm.object_id) AS object_name, o.type, o.type_ ...
- java字符串分解 StringTokenizer用法(比split()方法效率高)
Java中substring方法可以分解字符串,返回的是原字符串的一个子字符串.如果要讲一个字符串分解为一个一个的单词或者标记,StringTokenizer可以帮你. int countTokens ...
- SQL Server 中截取字符串常用的函数
SQL Server 中截取字符串常用的函数: 1.LEFT ( character_expression , integer_expression ) 函数说明:LEFT ( '源字符串' , '要 ...
- sql server中截取字符串的常用函数
我们如果要在sql server中,使用截取字符串的方法要怎样使用呢? sql server提供了3个常用截取字符串方法,LEFT().RIGHT().SUBSTRING() /****** Sql ...
- Sql动态查询拼接字符串的优化
Sql动态查询拼接字符串的优化 最原始的 直接写:string sql="select * from TestTables where 1=1";... 这样的代码效率很低的,这样 ...
- java字符串分解 StringTokenizer用法
Java中substring方法可以分解字符串,返回的是原字符串的一个子字符串.如果要讲一个字符串分解为一个一个的单词或者标记,StringTokenizer可以帮你. 先看个例子: 1 public ...
- XE4 TStringDynArray 比 c6 的TStringList 好用 字符串 分解 分割 转换 TByteDynArray
TStringDynArray 动态数组 字符串 分解 分割 System::DynamicArray<System::UnicodeString> TByteDynArray, ...
随机推荐
- c#开发工具软件集合
visual studio 2015(自带Nuget) Resharper de4dot dnspy ILMergeGui Git 大漠插件3.1233 天使插件v4.019 Navicat_Prem ...
- WebApi传参总动员(二)
上篇,从最简单的string入手.本篇演示了从请求的输入流中获取实体.api: public class ValuesController : ApiController { [HttpPost] p ...
- oracle 查询 当前最大时间的value的值
数据列表: table : text id datetime name value 1 2015-03-1 张三 3400 2 2015-03-1 ...
- .NET中Debug模式与Release模式
Visual Studio 项目对程序的发布和调试版本分别有单独的配置.顾名思义,生成调试版本的目的是用于调试,而生成发布版本的目的是用于版本的最终分发. 如果在 Visual Studio 中创建程 ...
- SQL Server SQL语句执行顺序
执行顺序: 1.FROM:对FROM子句中前两个表执行笛卡尔积生成虚拟表vt1 2.ON:对vt1表应用ON筛选器只有满足 为真的行才被插入vt2 3.OUTER(join):如果指定了 OUTER ...
- 2013 最新的 play web framework 版本 1.2.3 框架学习文档整理
Play framework框架学习文档 Play framework框架学习文档 1 一.什么是Playframework 3 二.playframework框架的优点 4 三.Play Frame ...
- Java集合 Json集合之间的转换
1. Java集合转换成Json集合 关键类:JSONArray jsonArray = JSONArray.fromObject(Object obj); 使用说明:将Java集合对象直接传进JSO ...
- VS2015发布Webservice
第一步:开启IIs:在控制面板程序——>程序功能——>打开或关闭windows功能,把“Internet信息服务”下面的“FTP服务器”.“Web管理工具”.“万维网服务”全部勾上,然后点 ...
- Android 优秀的开源框架整理
第一部分:系统架构 thinkAndroid https://github.com/white-cat/ThinkAndroid ThinkAndroid是一个免费的开源的.简易的.遵循Apache2 ...
- 物联网网络编程、Web编程综述
本文是基于嵌入式物联网研发工程师的视觉对网络编程和web编程进行阐述.对于专注J2EE后端服务开发的童鞋们来说,这篇文章可能稍显简单.但是网络编程和web编程对于绝大部分嵌入式物联网工程师来说是一块真 ...