在DB2中拆分VARCHAR以检索其中的值

时间:2022-08-28 21:45:51

I have a VARCHAR column that contains 5 informations (2 CHAR(3) and 3 TIMESTAMP) separated with '$'.

我有一个VARCHAR列,其中包含5个以'$'分隔的信息(2个CHAR(3)和3个TIMESTAMP)。

CREATE TABLE MYTABLE (
  COL VARCHAR(256) NOT NULL
);

INSERT INTO MYTABLE 
VALUES
    ( 'AAA$000$2009-10-10 10:50:00$null$null$null' ),
    ( 'AAB$020$2007-04-10 10:50:00$null$null$null' ),
    ( 'AAC$780$null$2007-04-10 10:50:00$2009-04-10 10:50:00$null' )
;

I would like to extract the 4th field ...

我想提取第4场......

'AAA$000$2009-10-10 10:50:00$null$null$null'
                             ^^^^ this field

... to have something like

......有类似的东西

SELECT SPLIT(COL, '$', 4) FROM MYTABLE

1
-----
'null'
'null'
'2009-04-10 10:50:00'

I'm searching, in that order :

我按顺序搜索:

  1. A DB2 build-in string function
  2. DB2内置字符串函数

  3. An embeddable statement such as SUBSTR(COL, POSSTR(COL)+1)...
  4. 一个可嵌入的语句,如SUBSTR(COL,POSSTR(COL)+1)......

  5. An user defined function that behaves like SPLIT
  6. 用户定义的函数,其行为类似于SPLIT

Precision : Yes, I do know that it's not a good idea to have such columns...

精度:是的,我知道拥有这样的专栏并不是一个好主意......

4 个解决方案

#1


6  

CREATE FUNCTION split(pos INT, delimeter CHAR, string VARCHAR(255))
LANGUAGE SQL
RETURNS VARCHAR(255)
DETERMINISTIC NO EXTERNAL ACTION
BEGIN ATOMIC
    DECLARE x INT;
    DECLARE s INT;
    DECLARE e INT;

    SET x = 0;
    SET s = 0;
    SET e = 0;

    WHILE (x < pos) DO
        SET s = locate(delimeter, string, s + 1);
        IF s = 0 THEN
            RETURN NULL;
        END IF;
        SET x = x + 1;
    END WHILE;

    SET e = locate(delimeter, string, s + 1);
    IF s >= e THEN
        SET e = LENGTH(string) + 1;
    END IF;
    RETURN SUBSTR(string, s + 1, e - s -1);
END!

Usage:

SELECT split(3,'$',col) from mytable; -- or
SELECT split(0,'-', 'first-second-third') from sysibm.sysdummy1;
SELECT split(0,'-', 'returns this') from sysibm.sysdummy1;
SELECT split(1,'-', 'returns null') from sysibm.sysdummy1;

#2


4  

I am sure there is a better way to write this, but here is 1 (SQL) solution for the simple case given. It could be rewritten as a stored procedure to look for any arbitrary string. There may also be some 3rd party tools/extensions to help out w/ the split you want...

我确信有更好的方法来编写它,但这里给出的是简单情况的1(SQL)解决方案。它可以重写为存储过程以查找任意字符串。可能还有一些第三方工具/扩展来帮助你解决你想要的分裂......

select
locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1) as poss3rdDollarSign, -- position of 3rd dollar sign
locate('$', col, (locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)) + 1) as poss4thDollarSign, -- position of 4th dollar sign
    (locate('$', col, (locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)) + 1)) - 
    (locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)) - 1  as stringLength,-- length of string between 3rd and 4th dollar sign
    substr(col, locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)  + 1, (locate('$', col, (locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)) + 1)) - 
    (locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)) - 1) as string
    from mytable

#3


1  

try this, it works!

试试这个,它有效!

CREATE FUNCTION SPLIT( P_1 VARCHAR(3200),
                       P_2 VARCHAR(200))
    RETURNS TABLE(P_LIST VARCHAR(3200))
    SPECIFIC SPLIT
    LANGUAGE SQL
    MODIFIES SQL DATA
    NO EXTERNAL ACTION
F1: BEGIN
    return
    with source(str, del) as
        (select p_1, p_2 from sysibm.sysdummy1),
            target(str, del) as
            (select source.str, source.del from source
                where length(source.str) > 0
         union all
            select 
            (case when (instr(target.str, target.del) > 0) 
                                    then substr(target.str, 
                                                 instr(target.str, target.del)+1, 
                                                   length(target.str)-instr(target.str, target.del))                                  else null end),
                (case when (instr(target.str, target.del) > 0) 
                                              then target.del else null end)
                from target
                where length(target.str) > 0
                )
        select str from target
        where str is not null;
END

#4


0  

If your DB2's version can do it, you can use then LOCATE_IN_STRING function for to found position of your separator. The LOCATE_IN_STRING function returns the starting position of a string and enable you to choice the Nth instance. You can found documentation of this function here

如果您的DB2版本可以执行此操作,则可以使用LOCATE_IN_STRING函数来查找分隔符的位置。 LOCATE_IN_STRING函数返回字符串的起始位置,并允许您选择第N个实例。您可以在此处找到此功能的文档

For your example, you can use this code :

对于您的示例,您可以使用以下代码:

select 
substring(col, LOCATE_IN_STRING(col, '$', 1, 3), LOCATE_IN_STRING(col, '$', 1, 4) - LOCATE_IN_STRING(col, '$', 1, 3))                       
from MYTABLE                                            

#1


6  

CREATE FUNCTION split(pos INT, delimeter CHAR, string VARCHAR(255))
LANGUAGE SQL
RETURNS VARCHAR(255)
DETERMINISTIC NO EXTERNAL ACTION
BEGIN ATOMIC
    DECLARE x INT;
    DECLARE s INT;
    DECLARE e INT;

    SET x = 0;
    SET s = 0;
    SET e = 0;

    WHILE (x < pos) DO
        SET s = locate(delimeter, string, s + 1);
        IF s = 0 THEN
            RETURN NULL;
        END IF;
        SET x = x + 1;
    END WHILE;

    SET e = locate(delimeter, string, s + 1);
    IF s >= e THEN
        SET e = LENGTH(string) + 1;
    END IF;
    RETURN SUBSTR(string, s + 1, e - s -1);
END!

Usage:

SELECT split(3,'$',col) from mytable; -- or
SELECT split(0,'-', 'first-second-third') from sysibm.sysdummy1;
SELECT split(0,'-', 'returns this') from sysibm.sysdummy1;
SELECT split(1,'-', 'returns null') from sysibm.sysdummy1;

#2


4  

I am sure there is a better way to write this, but here is 1 (SQL) solution for the simple case given. It could be rewritten as a stored procedure to look for any arbitrary string. There may also be some 3rd party tools/extensions to help out w/ the split you want...

我确信有更好的方法来编写它,但这里给出的是简单情况的1(SQL)解决方案。它可以重写为存储过程以查找任意字符串。可能还有一些第三方工具/扩展来帮助你解决你想要的分裂......

select
locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1) as poss3rdDollarSign, -- position of 3rd dollar sign
locate('$', col, (locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)) + 1) as poss4thDollarSign, -- position of 4th dollar sign
    (locate('$', col, (locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)) + 1)) - 
    (locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)) - 1  as stringLength,-- length of string between 3rd and 4th dollar sign
    substr(col, locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)  + 1, (locate('$', col, (locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)) + 1)) - 
    (locate('$', col, (locate('$',col, (locate('$',col) +1))) + 1)) - 1) as string
    from mytable

#3


1  

try this, it works!

试试这个,它有效!

CREATE FUNCTION SPLIT( P_1 VARCHAR(3200),
                       P_2 VARCHAR(200))
    RETURNS TABLE(P_LIST VARCHAR(3200))
    SPECIFIC SPLIT
    LANGUAGE SQL
    MODIFIES SQL DATA
    NO EXTERNAL ACTION
F1: BEGIN
    return
    with source(str, del) as
        (select p_1, p_2 from sysibm.sysdummy1),
            target(str, del) as
            (select source.str, source.del from source
                where length(source.str) > 0
         union all
            select 
            (case when (instr(target.str, target.del) > 0) 
                                    then substr(target.str, 
                                                 instr(target.str, target.del)+1, 
                                                   length(target.str)-instr(target.str, target.del))                                  else null end),
                (case when (instr(target.str, target.del) > 0) 
                                              then target.del else null end)
                from target
                where length(target.str) > 0
                )
        select str from target
        where str is not null;
END

#4


0  

If your DB2's version can do it, you can use then LOCATE_IN_STRING function for to found position of your separator. The LOCATE_IN_STRING function returns the starting position of a string and enable you to choice the Nth instance. You can found documentation of this function here

如果您的DB2版本可以执行此操作,则可以使用LOCATE_IN_STRING函数来查找分隔符的位置。 LOCATE_IN_STRING函数返回字符串的起始位置,并允许您选择第N个实例。您可以在此处找到此功能的文档

For your example, you can use this code :

对于您的示例,您可以使用以下代码:

select 
substring(col, LOCATE_IN_STRING(col, '$', 1, 3), LOCATE_IN_STRING(col, '$', 1, 4) - LOCATE_IN_STRING(col, '$', 1, 3))                       
from MYTABLE