将逗号分隔数据转换为多值IN列表

2010-03-15 11:16:59|  分类: 数据库技术|举报|字号 订阅

 
 

原文:http://book.csdn.net/bookfiles/530/10053017906.shtml

6.11       将分隔数据转换为多值IN列表

问题

已经有了分隔数据,想要将其转换为WHERE子句IN列表中的项目。考虑下面的字符串:

7654,7698,7782,7788

要将该字符串用在WHERE子句中,但是下面的SQL语句是错误的,因为EMPNO是一个数值列:

select ename,sal,deptno

from emp

where empno in ( '7654,7698,7782,7788' )

因为EMPNO是一个数值列,而此IN列表是一个字符串值,所以此SQL语句会失败。现要将此字符串转换为用逗号分解的数值列表。

解决方案

表面上看SQL应该将分隔字符串作为一个分隔值列表对待,但是实际情况不是这样。当SQL遇到括在引号中的逗号时,并不知道此符号表示多值列表,SQL必须将括在引号中的内容作为一个整体对待,也就是一个字符串值。因此必须将字符串分解为各个单独的EMPNO。这种解决方案的关键就是需要遍历字符串,但并不是一个字符一个字符地遍历,而是要将这个字符串转换为有效的EMPNO值。

DB2

通过遍历传递给IN列表的字符串,可以很轻松地将其转换为若干行。在这里函数ROW_NOMBER、LOCATE和SUBSTR尤其有用:

1  select empno,ename,sal,deptno

2    from emp

3   where empno in (

4  select cast(substr(c,2,locate(',',c,2)-2) as integer) empno

5    from (

6  select substr(csv.emps,cast(iter.pos as integer)) as c

7    from (select ','||'7654,7698,7782,7788'||',' emps

8            from t1) csv,

9         (select id as pos

10            from t100 ) iter

11   where iter.pos <= length(csv.emps)

12          )  x

13    where length(c) > 1

14      and substr(c,1,1) = ','

15          )  y

MySQL

通过遍历传递给IN列别的字符串,可以很轻松地将其转换为若干行:

1 select empno, ename, sal, deptno

2   from emp

3  where empno in

4        (

5 select substring_index(

6        substring_index(list.vals,',',iter.pos),',',-1) empno

6   from (select id pos from t10) as iter,

7        (select '7654,7698,7782,7788' as vals

8           from t1) list

9  where iter.pos <=

10        (length(list.vals)-length(replace(list.vals,',','')))+1

11        )  x

Oracle

通过遍历传递给IN列别的字符串,可以很轻松地将其转换为若干行。这里函数ROWNUM,SUBSTR和INSTR尤其有用:

1 select empno,ename,sal,deptno

2   from emp

3  where empno in (

4        select to_number(

5                   rtrim(

6                  substr(emps,

7                   instr(emps,',',1,iter.pos)+1,

8                   instr(emps,',',1,iter.pos+1) -

9                   instr(emps,',',1,iter.pos)),',')) emps

10          from (select ','||'7654,7698,7782,7788'||',' emps from t1) csv,

11               (select rownum pos from emp) iter

12         where iter.pos <= ((length(csv.emps)-

13                   length(replace(csv.emps,',')))/length(','))-1

14  )

Postgres

通过遍历传递给IN列别的字符串,可以很轻松地将其转换为若干行。使用函数 SPLIT_PART可以简化将字符串解析为单独的数值列表的工作:

1 select ename,sal,deptno

2   from emp

3  where empno in (

4 select cast(empno as integer) as empno

5   from (

6 select split_part(list.vals,',',iter.pos) as empno

7   from (select id as pos from t10) iter,

8        (select ','||'7654,7698,7782,7788'||',' as vals

9           from t1) list

10  where iter.pos <=

11        length(list.vals)-length(replace(list.vals,',',''))

12        )  z

13  where length(empno) > 0

14        )  x

SQL Server

通过遍历传递给IN列别的字符串,可以很轻松地将其转换为若干行。这里函数ROW_NUMBER、CHARINDEX和SUBSTRING尤其有用:

1 select empno,ename,sal,deptno

2   from emp

3  where empno in (select substring(c,2,charindex(',',c,2)-2) as empno

4   from (

5 select substring(csv.emps,iter.pos,len(csv.emps)) as c

6   from (select ','+'7654,7698,7782,7788'+',' as emps

7           from t1) csv,

8        (select id as pos

9          from t100) iter

10  where iter.pos <= len(csv.emps)

11        )  x

12  where len(c) > 1

13    and substring(c,1,1) = ','

14        )  y

讨论

这种解决方案中第一步,也是最重要的一步就是遍历字符串。一旦完成了这步操作,剩下的操作就是使用DBMS提供的函数来将字符串解析为单独的数值。

DB2和SQL Server

内联视图X(第6~11行)遍历字符串,这里用的是“穿越”字符串的思想,所以其每一行都比其上一行少一个字符:

,7654,7698,7782,7788,

7654,7698,7782,7788,

654,7698,7782,7788,

54,7698,7782,7788,

4,7698,7782,7788,

,7698,7782,7788,

7698,7782,7788,

698,7782,7788,

98,7782,7788,

8,7782,7788,

,7782,7788,

7782,7788,

782,7788,

82,7788,

2,7788,

,7788,

7788,

788,

88,

8,

,

注意,因为整个字符串是由逗号(分界符)括起来的,所以不需要特殊的检查来确定字符串从哪里开始及到哪里结束:

下一步是只保留要用于内部列表中的值。除了最后只有单独逗号的一行之外,保留以逗号开头的行。使用SUBSTR或SUBSTRING函数来识别哪些行以逗号开头,并保留在此行中到下一个逗号之间的所有字符。此操作完成后,将字符串转换为数值,这样就可以用来正确地跟数值列EMPNO运算了(行4~14):

EMPNO

------

7654

7698

7782

7788

最后,使用在子查询中的结果来返回想要得到的行。

MySQL

内联视图(行5~9)遍历字符串。第10行的表达式通过查找逗号(分隔符)的数量来确定在字符串中有多少个值并加1。函数SUBSTRING_INDEX(第6行)返回在字符串中第n个逗号(分隔符)之前(到它左边)的所有字符:

+---------------------+

| empno               |

+---------------------+

| 7654                |

| 7654,7698           |

| 7654,7698,7782      |

| 7654,7698,7782,7788 |

+---------------------+

这些行随后传递给SUBSTRING_INDEX(第5行)函数的另一次调用,此时第n个分隔符参数为-1,这表示在第n个分隔符右边所有的值需要保留。

+-------+

| empno |

+-------+

| 7654  |

| 7698  |

| 7782  |

| 7788  |

+-------+

最后一步是将结果加入到一个子查询中。

Oracle

第一步是遍历字符串:

select emps,pos

from (select ','||'7654,7698,7782,7788'||',' emps

from t1) csv,

(select rownum pos from emp) iter

where iter.pos <=

((length(csv.emps)-length(replace(csv.emps,',')))/length(','))-1

EMPS                         POS

--------------------- ----------

,7654,7698,7782,7788,          1

,7654,7698,7782,7788,          2

,7654,7698,7782,7788,          3

,7654,7698,7782,7788,          4

有多少行返回,就表示在列表中有多少个值。POS值对于查询是至关重要的,因为要用它来将字符串分解为单独的值。使用SUBSTR和INSTR函数来分解字符串,POS用来确定在每个字符串中第n个分隔符的位置。由于字符串是用逗号括起来的,所以不需要特殊的检测手段来确定字符串的开始位置与结束位置。传递给SUBSTR,INSTR(7~9行)确定第n个和第n+1个分隔符的位置。用下一个逗号的位置值(字符串中下一个逗号的位置)减去当前逗号的位置值(字符串中当前逗号的位置),就可以从字符串中提取出每个值。

select substr(emps,

instr(emps,',',1,iter.pos)+1,

instr(emps,',',1,iter.pos+1) -

instr(emps,',',1,iter.pos)) emps

from (select ','||'7654,7698,7782,7788'||',' emps

from t1) csv,

(select rownum pos from emp) iter

where iter.pos <=

((length(csv.emps)-length(replace(csv.emps,',')))/length(','))-1

EMPS

-----------

7654,

7698,

7782,

7788,

最后一步就是删除每个值后面的逗号,将其转换为数值并且将其插入到子查询中。

PostgreSQL

内联视图Z(6~9行)遍历字符串,返回行的数量也就是在字符串中有多少值。要找出在字符串中有多少值,用带有分隔符的字符串长度减去不带分隔符的字符串长度即可(第9行),函数SPLIT_PART用来分解字符串,该函数查找第n个分隔符之前的值。

SELECT列表.vals,

split_part(list.vals,',',iter.pos) as empno,

iter.pos

from (select id as pos from t10) iter,

(select ','||'7654,7698,7782,7788'||',' as vals

from t1) list

where iter.pos <=

length(list.vals)-length(replace(list.vals,',',''))

vals          | empno | pos

-----------------------+-------+-----

,7654,7698,7782,7788, |       |   1

,7654,7698,7782,7788, | 7654  |   2

,7654,7698,7782,7788, | 7698  |   3

,7654,7698,7782,7788, | 7782  |   4

,7654,7698,7782,7788, | 7788  |   5

最后一步就是将返回值(EMPNO)转换为数值,并且插入到子查询中。

db2 将逗号分隔数据转换为多值IN列表的更多相关文章

  1. 6.11 将分割数据转换为多值IN列表

    问题 已经有了分隔数据,想要将其转换为WHERE子句IN列表中的项目.考虑下面的字符串: 7654,7698,7782,7788 要将该字符串用在WHERE子句中,但是下面的SQL语句是错误的,因为E ...

  2. .net c#将数据库数据对象转换为实体值对象

    using System; using System.Data; namespace Sunlib { public static class DataHelper { //将数据库数据对象转换为实体 ...

  3. c语言实现灰度图转换为二值图

    将上篇得到的灰度图转换为二值图,读取像素数据,低于某一值置0,否则设置为255,为得到更好的效果不同图片应采用不同的值 /* 2015年6月2日11:16:22 灰度图转换为二值图 blog:http ...

  4. 使用python将mysql数据库的数据转换为json数据

    由于产品运营部需要采用第三方个推平台,来推送消息.如果手动一个个键入字段和字段值,容易出错,且非常繁琐,需要将mysql的数据转换为json数据,直接复制即可. 本文将涉及到如何使用Python访问M ...

  5. 将逗号分隔的字符串转换为Python中的列表

    给定一个字符串: 它是由逗号分隔的几个值的序列: mStr = '192.168.1.1,192.168.1.2,192.168.1.3' 如何将字符串转换为列表? mStr = ['192.168. ...

  6. 深度学习原理与框架-Tfrecord数据集的制作 1.tf.train.Examples(数据转换为二进制) 3.tf.image.encode_jpeg(解码图片加码成jpeg) 4.tf.train.Coordinator(构建多线程通道) 5.threading.Thread(建立单线程) 6.tf.python_io.TFR(TFR读入器)

    1. 配套使用: tf.train.Examples将数据转换为二进制,提升IO效率和方便管理 对于int类型 : tf.train.Examples(features=tf.train.Featur ...

  7. 深度学习原理与框架-递归神经网络-时间序列预测(代码) 1.csv.reader(进行csv文件的读取) 2.X.tolist(将数据转换为列表类型)

    1. csv.reader(csvfile) # 进行csv文件的读取操作 参数说明:csvfile表示已经有with oepn 打开的文件 2. X.tolist() 将数据转换为列表类型 参数说明 ...

  8. 将日期或数据转换为char数据类型 TO_CHAR(x[[,c2],C3])

    TO_CHAR(x[[,c2],C3])[功能]将日期或数据转换为char数据类型[参数]x是一个date或number数据类型.c2为格式参数c3为NLS设置参数如果x为日期nlsparm=NLS_ ...

  9. pandas神坑:如果列有NAN,则默认给数据转换为float类型!给pandas列指定不同的数据类型。

    今天碰到一个错误,一个字典取值报keyError, 一查看key, 字符串类型的数字后面多了小数点0, 变成了float的样子了. 发现了pandas一个坑:如果列有NAN,则默认给数据转换为floa ...

随机推荐

  1. MVC中cshtml文件中怎样使用ViewBag进行筛选?

    @foreach (PermissionForRoleModel item in ((List<PermissionForRoleModel>)ViewBag.PermissionsFor ...

  2. 机器学习数学基础- gradient descent算法(上)

    为什么要了解点数学基础 学习大数据分布式计算时多少会涉及到机器学习的算法,所以理解一些机器学习基础,有助于理解大数据分布式计算系统(比如spark)的设计.机器学习中一个常见的就是gradient d ...

  3. 18-spring学习-AOP深入操作

    范例:定义一个参数拦截 package com.Spring.aop; import org.springframework.stereotype.Component; @Component publ ...

  4. SQL数据库异地备份

    服务器:windows sever 2008(简称为A) 数据库:SQL server 2008 R2(安装在A上) 普通台式机:windows 7(简称为B) 目的:将A中的数据定时自动备份到B中 ...

  5. PHP-php.ini中文版

    今天细看了下配置文件 有很多没用过的 就从网上搜了一篇 常看看 ;;;;;;;;;;;;;;;; 简介 ;;;;;;;;;;;;;;;;; 本文并非是对英文版 php.ini 的简单翻译,而是参考了众 ...

  6. 关闭windows打印服务

    1.关闭打印服务:开始-运行-services.msc或打开控制面板-管理工具-服务,打开服务列表,找到Print Spooler(打印服务),关闭(右击,点“关闭”).2.删除打印缓存:进入c:\\ ...

  7. Java Persistence with MyBatis 小结3

    1 映射器配置文件和映射器接口 在 com.mybatis3.mappers 包中的 StudentMapper.xml 配置文件内,是如何配置 id 为”findStudentById”的 SQL ...

  8. java开发中国际化

    1 静态文本的国际化,就是比如页面中中文显示用户名就是用户名,用于显示就是 username. 其中静态文件命名遵循:基础名_语言简称_国家简称.properties 需要使用的类是 1)import ...

  9. python核心编程——python对象

    一.什么是python对象 在python中,构造的不论什么类型的值都是一个对象.比方一个整数类型的值,一个字符串.一个列表等,都能够看做是对象. 全部的对象分为三部分: (1)身份.每一个对象都有个 ...

  10. java synchronized究竟锁住的是什么

    刚学java的时候,仅仅知道synchronized一个线程锁.能够锁住代码,可是它真的能像我想的那样,能够锁住代码吗? 在讨论之前先看一下项目中常见关于synchronized的使用方法: publ ...