在DB2 / DB2400中选择逗号分隔字符串的一部分

时间:2015-05-01 07:38:23

标签: sql db2 db2-400

我需要仅使用SQL在逗号分隔的字符串中选择一个值。这可能吗?

2nd item in column C

我需要特别选择SQL,在这种情况下是香蕉。我需要帮助。我无法创建新的SQL函数,我只能使用as400。这是SQL,因此SELECT xmlcast(xmlquery('$x/Names/Name[2]' passing xmlparse(document CONCAT(CONCAT('<?xml version="1.0" encoding="UTF-8" ?><Names><Name>',REPLACE(ODWDATA,',','</Name><Name>')),'</Name></Names>')) as "x") as varchar(1000)) FROM ACL00 有些旧技术。

更新.. 在@Sandeep的帮助下,我们能够提出

Keyword PASSING not expected. Valid tokens: ) ,. 

我收到此错误

${sessionScope.config_menu}

新的更新。使用Oracle的INSTR的UDF解决了问题

5 个答案:

答案 0 :(得分:1)

如果您只想要第二项,则可以使用子串函数:

DECLARE @TABLE TABLE
(
    A INT,
    B VARCHAR(100),
    C VARCHAR(100)
)

DECLARE @NTH INT = 3

INSERT INTO @TABLE VALUES (1,'Luigi','Apple,Banana,Pineapple,,Citrus')

SELECT REPLACE(REPLACE(CAST(CAST('<Name>'+ REPLACE(C,',','</Name><Name>') +'</Name>' AS XML).query('/Name[sql:variable("@NTH")]') AS VARCHAR(1000)),'<Name>',''),'</Name>','') FROM @TABLE

答案 1 :(得分:1)

我假设我不使用db2,所以下面的语法可能不会发生,但方法可行。

在Oracle中,我使用INSTR()和SUBSTR(),谷歌建议使用LOCATE()和SUBSTR()为db2

使用LOCATE获取第一个逗号的位置,并在SUBSTR中使用该值来获取在第一个逗号后面开始的YourColumn的结尾

SUBSTR(YourColumn, LOCATE(YourColumn, ',') + 1)

你开始使用“Apple,Banana,Pineapple ,, Citrus”,你现在应该有“Banana,Pineapple ,, Citrus”,所以我们在上面返回的字符串上再次使用LOCATE和SUBSTR。

SUBSTR(SUBSTR(YourColumn, LOCATE(YourColumn, ',') + 1), 1, LOCATE(SUBSTR(YourColumn, LOCATE(YourColumn, ',') + 1), ',') - 1)

第一个SUBSTR正在获取字符串的右侧,所以我们只需要一个起始位置参数,第二个SUBSTR正在抓取字符串的左侧,所以我们需要两个,开始位置和返回的长度。

答案 2 :(得分:1)

更漂亮的解决方案 IMO 将封装来自列C的数据的递归公用表表达式(递归CTE又称RCTE)以生成结果TABLE [即用户定义表函数(表UDF又名UDTF)]然后使用标量子选择来选择哪个有效记录\行号。

  select
    a
  , b
  , ( select S.token_vc
      from table( split_tokens(c) ) as S
      where S.token_nbr = 2
    ) as "2nd Item of column C"
  from The_Table /* in OP described with columns a,b,c but no DDL */

更漂亮的是将同一RCTE的结果作为标量值,以便允许简单地作为标量UDF调用,其中有效行号[作为另一个参数]明确定义要选择的元素。

  select
    a
  , b
  , split_tokens(c, 2) as "2nd Item of column C"
  from The_Table /* in OP described with columns a,b,c but no DDL */

后者可以更有效,将RCTE产生的行数据限制为仅需要的编号标记和编号标记之前的标记。与提供的任何其他答案相比,我无法评论关于对CPU和存储的影响的效率,但我自己对临时存储实施的经验和RCTE结果的整体快速性是积极的,特别是当其他行选择限制了必须为整个查询请求生成的派生表结果的数量时。

UDF [和\或UDTF以及实现它们的RCTE]留给读者练习;主要是因为我没有一个支持递归表表达式的发行版系统。如果被要求[例如在对回答]的评论中,我可以提供未经测试的代码来源。

答案 3 :(得分:1)

在这种情况下,我发现locate_in_string函数可以很好地工作。

select substr(
              c, 
              locate_in_string(c, ',')+1, 
              locate_in_string(c, ',', locate_in_string(c, ',')+1) - locate_in_string(c, ',')-1
              ) as fruit2
  from ACL00 for read only with ur;

答案 4 :(得分:0)

我现在正在回答我自己的问题。使用built in functions within AS400

无法做到这一点

您必须创建Oracle的INSTR

的UDF

在STRSQL中输入它将创建一个名为INSTRB

的新函数
CREATE FUNCTION INSTRB (C1 VarChar(4000), C2 VarChar(4000), N integer, M integer)
 RETURNS Integer
 SPECIFIC INSTRBOracleBase
 LANGUAGE SQL
 CONTAINS SQL
 NO EXTERNAL ACTION
 DETERMINISTIC
BEGIN ATOMIC
DECLARE Pos, R, C2L Integer;

SET C2L = LENGTH(C2);

IF N > 0 THEN
   SET (Pos, R) = (N, 0);
   WHILE R < M AND Pos > 0 DO
      SET Pos = LOCATE(C2,C1,Pos);
         IF Pos > 0 THEN
         SET (Pos, R) = (Pos + 1, R + 1);
      END IF;
   END WHILE;

   RETURN (Pos - 1)*(1-SIGN(M-R));
ELSE
   SET (Pos, R) = (LENGTH(C1)+N, 0);
   WHILE R < M AND Pos > 0 DO
      IF SUBSTR(C1,Pos,C2L) = C2 THEN
         SET R = R + 1;
      END IF;
      SET Pos = Pos - 1;
   END WHILE;

   RETURN (Pos + 1)*(1-SIGN(M-R));
END IF;

END

然后在逗号分隔的字符串中选择第n个分隔值...在本例中为第14个

使用新功能

使用此查询
SELECT SUBSTRING(C,INSTRB(C,',',1,13)+1,INSTRB(C,',',1,14)-INSTRB(C,',',1,13)-1) FROM TABLE