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

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

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

下面的代码使用到了分析函数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. jquery ajax跨域访问webservice配置

    1.webservice方法 [System.Web.Script.Services.ScriptService] public class TestService : System.Web.Serv ...

  2. 不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出

    [源码下载] 不可或缺 Windows Native (4) - C 语言: 预处理命令,输入,输出 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 预处理命令 输入 ...

  3. C# 修改电脑DNS和IP方法

    /// <summary> /// 将IP,DNS设置为自动获取 /// </summary> private void setDHCP() { string _doscmd ...

  4. ViewPager的使用

    在上培训课的时候,老师一直在将ViewPager是现在的主流,一直想去好好的了解一下,今天去网上学习了一下   ,做一个总结: ViewPager其实就是后来谷歌提供给我们的一个组件,就像TextVi ...

  5. Python正则表达式模块(re模块)

    Python是我接触到的第一门编程语言,虽然它足够简单,但是对于当时刚刚接触编程语言的我来说还是有些难度的,于是只是了解了一些Python的基本语法,稍微深入一点的地方都没怎么了解.不过,到现在为止, ...

  6. 开启Windows Server 2008 R2上帝模式

    TAG标签: 摘要:这个“God Mode” 应该大部分的网友都听过了,只是在 Windows Server 2008 R2 上也支持此一功能.启用方式非常简单,在桌面新建一个文件夹,命名为: God ...

  7. Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39

    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39 V1  初步实现sina csdn cnblogs V2  实现qzone sohu 的发帖 ...

  8. php 安全过滤函数代码

    php 安全过滤函数代码,防止用户恶意输入内容. //安全过滤输入[jb] function check_str($string, $isurl = false) { $string = preg_r ...

  9. Android群英传笔记系列三 view的自定义:实现一个模拟下载

    1.实现效果:动态显示进度(分别显示了整个的动态改变的过程,然后完成后,弹出一个对话框)       2.实现过程:可以分为绘制一个圆,圆弧和文本三部分,然后在MainAcitivity中通过线程模拟 ...

  10. 彻底退出所有的Acticity

    有时候点击回退键退出应用,会出现有些Activity不能完全退出的情况,那么可以使用前面这个方法: 在需要退出的Activity的onCreate()方法中加入 ExitApplication.get ...