如何在DB2中拆分字符串值?
例如,给定值:
CHG-FFH.
Run Code Online (Sandbox Code Playgroud)
我想拆分破折号( - ),这将产生两个值:
CHG
FFH.
Run Code Online (Sandbox Code Playgroud)
我尝试使用split函数,但它不是DB2中的函数.
任何帮助将不胜感激.
Jos*_*ull 22
简短回答:
您需要找到分隔符的位置,然后在它之前和之后查找子字符串.
SELECT
SUBSTR('CHG-FFH', 1, LOCATE('-','CHG-FFH')-1) as FIRST_PART
, SUBSTR('CHG-FFH', LOCATE('-','CHG-FFH')+1) as SECOND_PART
FROM SYSIBM.SYSDUMMY1;
Run Code Online (Sandbox Code Playgroud)
答案很长:
DB2以及其他关系数据库不提供单个功能来完成此任务.
原因很可能是它不是隐含的标量函数.如果您的字符串中包含多个短划线,您是否要将其拆分为三个部分?四?因此,第一步是要注意您的数据是否确定 - 如果它具有您要拆分的特定数量的组件.在你的例子中,你有两个,所以我将从这个假设开始,然后评论你将如何处理其他情况.
场景:一个字符串值,其中两个组件由分隔符分隔
只有两个部分,你需要找到分隔符的位置,然后通过在子字符串函数中使用它之前和之后的位置来查找它之前和之后的子字符串.
CREATE FUNCTION SPLITTER (input VARCHAR(4000), delimiter CHAR, part_number INTEGER)
RETURNS VARCHAR(4000)
LANGUAGE SQL
READS SQL DATA
NO EXTERNAL ACTION
DETERMINISTIC
RETURN
with pos_info (first_pos, length) as (
select
case when part_number = 1 then 0
else LOCATE_IN_STRING(input, delimiter,1, part_number-1, OCTETS)
end as first_pos,
case when part_number = 1 then LOCATE_IN_STRING(input, delimiter,1, part_number, OCTETS) - 1
when LOCATE_IN_STRING(input, delimiter,1, part_number, OCTETS) = 0
and LOCATE_IN_STRING(input, delimiter,1, part_number-1, OCTETS) = 0
then 0
when LOCATE_IN_STRING(input, delimiter,1, part_number, OCTETS) = 0
then length(input) - LOCATE_IN_STRING(input, '-',1, part_number - 1, OCTETS)
else LOCATE_IN_STRING(input, delimiter,1, part_number, OCTETS) - LOCATE_IN_STRING(input, delimiter,1, part_number-1, OCTETS) - 1
end as length
from sysibm.sysdummy1
)
select
substr(input, first_pos+1,length) as part
from pos_info;
Run Code Online (Sandbox Code Playgroud)
注意: DB2提供了两个可用于此的函数:POSITION(或POSSTR)和LOCATE(或LOCATE_IN_STRING).LOCATE更强大,因为它允许您指定起始位置,如果您有多个分隔符,这将有所帮助.
对于第一部分,从位置1开始子字符串,直到分隔符前面的字符(分隔符位置 - 1):
LOCATE('-','CHG-FFH')
Run Code Online (Sandbox Code Playgroud)
对于第二部分,在分隔符索引(分隔符位置+ 1)之后的位置启动子字符串,并获取字符串的其余部分:
SUBSTR('CHG-FFH', 1,LOCATE('-','CHG-FFH')-1) as FIRST_PART
Run Code Online (Sandbox Code Playgroud)
最后结果:
SUBSTR('CHG-FFH', LOCATE('-','CHG-FFH')+1) as SECOND_PART
Run Code Online (Sandbox Code Playgroud)
场景:具有由分隔符分隔的三个组件的字符串值
使用与第一个方案相同的概念,但您必须确定第二个分隔符的索引.使用第一个分隔符的索引来指定起始点:请注意,LOCATE允许指定起始位置:
SELECT
SUBSTR('CHG-FFH', 1,LOCATE('-','CHG-FFH')-1) as FIRST_PART
, SUBSTR('CHG-FFH', LOCATE('-','CHG-FFH')+1) as SECOND_PART
FROM SYSIBM.SYSDUMMY1;
Run Code Online (Sandbox Code Playgroud)
找到第二个分隔符:
使用第一个分隔符的位置作为查找第二个分隔符的起点.
>>-LOCATE(search-string,source-string-+--------+-+--------------------+-)-><
'-,start-' '-,--+-CODEUNITS16-+-'
+-CODEUNITS32-+
'-OCTETS------'
Run Code Online (Sandbox Code Playgroud)
使用它作为第二个和第三个值的SUBSTR点,你们都已经设置好了.注意:对于第二个值,您必须使用两个分隔符位置来对值进行子串.
最后结果:
LOCATE('-','CHG-FFH-EEE', LOCATE('-','CHG-FFH-EEE')+1)
Run Code Online (Sandbox Code Playgroud)
你可以看到这个策略在你的String中有更多的分隔符时会失控.
场景:不确定分隔符的数量
This is a tricky problem that is best approached with a Stored Procedure. Think through things like: How do you want the parsed data to come out of the algorithm, how will you access the data? Arrays are not a native type in SQL, but they are in Stored Procedures, so what will you do with the array when you've parsed all the pieces out of your String?
One way to approach this scenario is answered here:
Split a VARCHAR in DB2 to retrieve a value inside
这是我尝试过的,它为我带来了有效的结果。因此与大家分享。
select column_name, substr(column_name,1,locate('-',column_name)-1),
substr(column_name,locate('-',column_name)+1,
length(substr(column_name,locate('-',column_name)+1))) from
table_name where column_name is not null and column_name!=''
and column_name like '%-%'
Run Code Online (Sandbox Code Playgroud)
小智 5
这么晚回答的原因是为了展示更简单和通用的方法来实现目标。它基于使用正则表达式的函数,即使在提出问题时也可用。
SELECT
COL
-- since 9.7 (2009)
, xmlcast(xmlquery('fn:tokenize($s, "-")[2]' passing COL as "s") as varchar(20)) as one
-- since 11.1
, REGEXP_SUBSTR(COL, '([^-]*)-?', 1, 2, '', 1) as two
FROM (VALUES 'CHG-FFH.', 'ABC-DEF-GH') TAB (COL);
Run Code Online (Sandbox Code Playgroud)
结果是:
|COL |ONE |TWO |
|----------|--------------------|----------|
|CHG-FFH. |FFH. |FFH. |
|ABC-DEF-GH|DEF |DEF |
Run Code Online (Sandbox Code Playgroud)
-- since 9.7 (2009)
SELECT TAB.COL, TOK.SEQ, TOK.TOKEN
FROM
(VALUES 'CHG-FFH.', 'ABC-DEF-GH') TAB (COL)
, XMLTABLE
(
'for $id in tokenize($s, "-") return <i>{string($id)}</i>' PASSING TAB.COL AS "s"
COLUMNS
SEQ FOR ORDINALITY
, TOKEN VARCHAR(20) PATH '.'
) TOK
ORDER BY TAB.COL, TOK.SEQ;
Run Code Online (Sandbox Code Playgroud)
结果是:
|COL |SEQ |TOKEN |
|----------|--------------------|--------------------|
|ABC-DEF-GH|1 |ABC |
|ABC-DEF-GH|2 |DEF |
|ABC-DEF-GH|3 |GH |
|CHG-FFH. |1 |CHG |
|CHG-FFH. |2 |FFH. |
Run Code Online (Sandbox Code Playgroud)