【问题标题】:Split a VARCHAR in DB2 to retrieve a value inside在 DB2 中拆分 VARCHAR 以检索其中的值
【发布时间】:2010-11-21 07:20:08
【问题描述】:

我有一个 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' )
;

我想提取第四个字段...

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

...拥有类似的东西

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

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

我正在按顺序搜索:

  1. DB2 内置字符串函数
  2. 可嵌入语句,例如SUBSTR(COL, POSSTR(COL)+1)...
  3. 行为类似于SPLIT 的用户定义函数

Precision :是的,我确实知道拥有这样的列不是一个好主意...

【问题讨论】:

    标签: sql string db2 split


    【解决方案1】:
    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!
    

    用法:

    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;
    

    【讨论】:

    • 接受它,因为它正是我搜索的内容(第三个选项)。您可以添加DETERMINISTICNO EXTERNAL ACTION 修饰符,以便能够在GROUP BY 子句中使用它吗?
    • 好点。未找到元素时更改为返回 NULL。请求第一个元素,不存在deliemeter 将返回原始字符串。
    【解决方案2】:

    我确信有更好的方法来编写这个,但这里是针对给定简单案例的 1 (SQL) 解决方案。它可以重写为存储过程来查找任意字符串。也可能有一些第 3 方工具/扩展来帮助您进行拆分...

    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
    

    【讨论】:

    • +1 表示努力:-)。我也最终做了类似的事情,但我正在寻找更通用的东西。
    • 这很糟糕,但这正是我在查询中帮助我进行一些字符串解析所需要的。谢谢!
    • 感谢定位功能。帮助进行其他一些字符串解析,我需要将 VARCHAR 末尾带有 :USD 的字符转换为 DECMIAL。
    【解决方案3】:

    试试这个,它有效!

    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】:

    如果您的 DB2 版本可以做到这一点,您可以使用 LOCATE_IN_STRING 函数来找到分隔符的位置。 LOCATE_IN_STRING 函数返回字符串的起始位置,使您能够选择第 N 个实例。你可以找到这个函数的文档here

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

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

    【讨论】:

      【解决方案5】:
         substr(e.data,1,13) as NNSS,
         substring(e.data, LOCATE_IN_STRING(e.data, ';', 1, 1, CODEUNITS32)+1,  (LOCATE_IN_STRING(e.data, ';', 1, 2, CODEUNITS32) - LOCATE_IN_STRING(e.data, ';', 1, 1, CODEUNITS32)-1) ) as Name,  
         substring(e.data, LOCATE_IN_STRING(e.data, ';', 1, 2, CODEUNITS32)+1,  (LOCATE_IN_STRING(e.data, ';', 1, 3, CODEUNITS32) - LOCATE_IN_STRING(e.data, ';', 1, 2, CODEUNITS32)-1) ) as Vorname,
         substring(e.data, LOCATE_IN_STRING(e.data, ';', 1, 3, CODEUNITS32)+1,  (LOCATE_IN_STRING(e.data, ';', 1, 4, CODEUNITS32) - LOCATE_IN_STRING(e.data, ';', 1, 3, CODEUNITS32)-1) ) as Grund
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-09
        • 1970-01-01
        相关资源
        最近更新 更多