SQL 分隔数据转换为多值IN列表,你有一些分隔数据,想传递给 WHERE
子句的 IN
列表。考虑下面的字符串。
SQL 分隔数据转换为多值IN列表 问题描述
你有一些分隔数据,想传递给 WHERE
子句的 IN
列表。考虑下面的字符串。
你希望在 WHERE 子句里使用上述字符串,但是下面的 SQL 会由于 EMPNO
列是数值字段而执行失败。
上述 SQL 之所以失败是因为,EMPNO
列是数值类型,而 IN
列表里却只有一个字符串。你希望上述字符串能被当作逗号分隔的数值列表。
SQL 分隔数据转换为多值IN列表 解决方案
从表面上看,我们应该设法让 SQL 把分隔字符串当成一系列用逗号分隔好的值。然而,事实并非如此。如果一个逗号出现在引号里,SQL 无法知道它是一个多值列表。SQL 会把引号中的任何值当成单一的字符串数据。我们必须把该字符串打散,变成单个的 EMPNO
。本解决方案的关键之处在于遍历字符串,但是并不需要深入到每一个字符。只需要遍历字符串中每一个有效的 EMPNO
即可。
DB2
遍历传递给 IN
列表的字符串,我们很容易将其转换为行数据。在这里,函数 ROW_NUMBER
、LOCATE
和 SUBSTR
非常有用。
MySQL
遍历传递给 IN
列表的字符串,我们很容易将其转换为行数据。
Oracle
遍历传递给 IN
列表的字符串,我们很容易将其转换为行数据。在这里,ROWNUM
、SUBSTR
和 INSTR
非常有用。
PostgreSQL
遍历传递给 IN
列表的字符串,我们很容易将其转换为行数据。SPLIT_PART
函数能方便地把字符串解析成多个单独的数字。
SQL Server
遍历传递给 IN
列表的字符串,我们很容易将其转换为行数据。在这里,函数 ROW_NUMBER
、CHARINDEX
和 SUBSTRING
非常有用。
SQL 分隔数据转换为多值IN列表 扩展知识
这个解决方案的第一步就是遍历字符串,这也是最重要的一步。一旦你完成了这一步,那么剩下的就是解析字符串,用数据库提供的函数把字符串逐个转换为数值。
DB2 和 SQL Server
内嵌视图 X
(第 6 ~ 11 行)遍历字符串。该解决方案的思路就是遍历字符串,因此每一行都比它前面的那行少一个字符。
注意,字符串前后都有逗号(分隔符),因此不需要特意检查字符串的起止位置。
下一步就是只保留我们想要放在 IN
列表中的值。这些值都以逗号开头,但是要排除掉最后一行,因为最后一行只有一个孤零零的逗号。调用函数 SUBSTR
或 SUBSTRING
筛选出以逗号开头的行,然后在那一行里找到下一个逗号,并留下两个逗号之间的所有字符。这一步完成后,接着要把找到的字符串转换为数字,这样就可以针对数值类型的 EMPNO
列(第 4 ~ 14 行)进行适当的评估。
最后,把结果集放入一个子查询里,并返回想要得到的行。
MySQL
内嵌视图(第 5 ~ 9 行)遍历字符串。第 10 行的表达式决定了字符串里包含多少个值,这是通过找出字符串中有多少个逗号(分隔符)并加上 1 来实现的。函数 SUBSTRING_INDEX
(第 6 行)返回字符串中第 n 次出现逗号(分隔符)之前(从左边开始)的所有字符。
然后,上面得到的行会被再次传递给 SUBSTRING_INDEX
函数(第 5 行)。这一次的参数里,指定的第 n 次出现分隔符的参数值是 -1
,这意味着从右边数第 n 次出现分隔符后,其右侧所有字符都会被保留下来。
最后,将上述结果放入一个子查询中。
Oracle
第一步是遍历字符串。
上述查询返回的行数代表了列表中有多少个值。POS
列至关重要,有了它才能把字符串解析成单个的值。使用 SUBSTR
函数和 INSTR
函数解析字符串。POS
列被用来找出分隔符在每个字符串中第 n 次出现时的位置。由于字符串前后都有逗号,就不再需要做特别的检查来确定字符串的起止位置。被传递到函数 SUBSTR
和 INSTR
(第 7 ~ 9 行)的值能找出分隔符第 n 次和第 n+1 次出现的位置。通过使用下一个逗号(在字符串中下一个逗号出现的位置)的返回值减去当前逗号(在字符串中当前逗号所在的位置)的返回值,我们就能从字符串中提取出每一个值。
最后,删除每个值后面的逗号,将其转换为数字并放入子查询中。
PostgreSQL
内嵌视图 Z
(第 6 ~ 9 行)遍历字符串。返回的行数取决于字符串中含有多少个值。为了找出字符串中含有多少个值,用包含分隔符的字符串总长度减去去掉了分隔符的字符串长度(第 9 行)。SPLIT_PART
函数可以解析字符串,并找到分隔符第 n 次出现之前的那个值。
最后,把这些值(EMPNO
列)转换成数字,并将其放入子查询中。