本题不是一道直接的字符串拆解,

应用场景如下,表中有一个字段,是表示事件受影响的国家集合,使用逗号进行分隔,不幸的是,居然发现有些国家本身就带有逗号,这样在规范化的时候,如何准确地找到这些国家呢?

以下的代码是有一定限制的。但基本上够用。

下面的代码使用到了分析函数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-一道特殊的字符串分解题目的更多相关文章

  1. SQL Server中截取字符串常用函数

    SQL Server 中截取字符串常用的函数: .LEFT ( character_expression , integer_expression ) 函数说明:LEFT ( '源字符串' , '要截 ...

  2. 使用List把一个长字符串分解成若干个短字符串

    把一个长字符串分解成若干个固定长度的短字符串,由于事先不知道长字符串的长度,以及短字符串的数量,只能使用List. public static void get_list_sbody(String s ...

  3. sql server 查找包含字符串的对象

    sql server 查找包含字符串的对象 SELECT sm.object_id, OBJECT_NAME(sm.object_id) AS object_name, o.type, o.type_ ...

  4. java字符串分解 StringTokenizer用法(比split()方法效率高)

    Java中substring方法可以分解字符串,返回的是原字符串的一个子字符串.如果要讲一个字符串分解为一个一个的单词或者标记,StringTokenizer可以帮你. int countTokens ...

  5. SQL Server 中截取字符串常用的函数

    SQL Server 中截取字符串常用的函数: 1.LEFT ( character_expression , integer_expression ) 函数说明:LEFT ( '源字符串' , '要 ...

  6. sql server中截取字符串的常用函数

    我们如果要在sql server中,使用截取字符串的方法要怎样使用呢? sql server提供了3个常用截取字符串方法,LEFT().RIGHT().SUBSTRING() /****** Sql ...

  7. Sql动态查询拼接字符串的优化

    Sql动态查询拼接字符串的优化 最原始的 直接写:string sql="select * from TestTables where 1=1";... 这样的代码效率很低的,这样 ...

  8. java字符串分解 StringTokenizer用法

    Java中substring方法可以分解字符串,返回的是原字符串的一个子字符串.如果要讲一个字符串分解为一个一个的单词或者标记,StringTokenizer可以帮你. 先看个例子: 1 public ...

  9. XE4 TStringDynArray 比 c6 的TStringList 好用 字符串 分解 分割 转换 TByteDynArray

    TStringDynArray 动态数组  字符串 分解 分割  System::DynamicArray<System::UnicodeString> TByteDynArray,    ...

随机推荐

  1. Python入门笔记(8):列表

    一.序列类型操作符 1.切片[]和[:] 2.成员关系操作符(in ,not in ) 1: s1 = [1,2,3,4,5,6,7] 2: s2 = [2,3,6] 3: s3 = [] 4: fo ...

  2. jquery 字符串转dom对象及对该对象使用选择器查询

    <script> $(document).ready(function () { var htmlStr = '<div id="outerDiv">< ...

  3. vs2008不能创建C#项目的解决方法

    解决方法:1.先关闭 Visual Studio 2008 ;2.在运行中输入命令"devenv.exe /setup"3.运行 Visual Studio 2008 ,一切搞定. ...

  4. 行转列一定要sum

    --SELECT 姓名 ,-- 课程 ,-- 分数--FROM tb UNPIVOT ( 分数 FOR 课程 IN ( [语文], [数学], [物理] ) ) t --)

  5. MyBatis中的特殊符号[20160713]

    今天中午回到工位已经是12:20多了,没有时间睡觉了,本想着还能提前开始,结果看了点新闻之后,又是12:40了,所以新闻坚决不能看,执行力. 今天主要记录一下MyBatis中的特殊符号的问题,这个问题 ...

  6. 数组json格式的字符串 转 list<Bean>

    1.  字符串形式: [ { "userid": "admin", "name": "admin", "pas ...

  7. 两种设计模式(1)==>>“简单工厂”

    我们以做一个计算器为例,给大家介绍简单工厂的应用: 效果: 这里我们使用 继承 ,虚方法, 简单工厂的设计模式来完成 首先,我们除了搭好窗体外,我们应该把我们的一些类准备好: 1.计算的父类Calcu ...

  8. 【OpenCV & CUDA】OpenCV和Cuda结合编程

    一.利用OpenCV中提供的GPU模块 目前,OpenCV中已提供了许多GPU函数,直接使用OpenCV提供的GPU模块,可以完成大部分图像处理的加速操作. 基本使用方法,请参考:http://www ...

  9. IIS减少工作线程阻塞的方法

    IIS的工作进程(w3wp.exe)只提供了有限的工作线程(Work Thread)来处理请求.如果这些线程都因为要等待长时间运行的任务而阻塞,则运行时会将新来的请求排队,而不是立即执行,Web服务器 ...

  10. css复习笔记

    margin: 1. 当有三个值时第一个值为上,第二个值为左右,第三个值为下. 2.margin外边距折叠,水平没有,垂直会折叠,且折叠后以两者最大值为准.另外,当一个元素包裹另一元素时也会发生折叠. ...