Select DB2/DB2400 中逗号分隔字符串的一部分
Select a portion of a comma delimited string in DB2/DB2400
我需要 select 一个逗号分隔字符串中的值,仅使用 SQL。这可能吗?
Data
A B C
1 Luigi Apple,Banana,Pineapple,,Citrus
我需要 select 具体 2nd item in column C
,在本例中是香蕉。我需要帮助。我无法创建新的 SQL 函数,我只能使用 SQL
。这是 as400
所以 SQL
有点老技术了。
更新..
在@Sandeep 的帮助下,我们能够想出
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
我遇到了这个错误
Keyword PASSING not expected. Valid tokens: ) ,.
新更新。使用Oracle的INSTR
的UDF解决的问题
如果你只想要第二项,你可以使用子字符串函数:
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
我假设我不使用 db2,因此以下语法可能不适用,但该方法有效。
在 Oracle 中,我会使用 INSTR() 和 SUBSTR(),Google 建议为 db2 使用 LOCATE() 和 SUBSTR()
使用 LOCATE 获取第一个逗号的位置,并在 SUBSTR 中使用该值获取第一个逗号后开始的 YourColumn 的末尾
SUBSTR(YourColumn, LOCATE(YourColumn, ',') + 1)
您从 "Apple,Banana,Pineapple,,Citrus" 开始,现在应该 "Banana,Pineapple,,Citrus",所以我们再次对上面的 returned 字符串使用 LOCATE 和 SUBSTR。
SUBSTR(SUBSTR(YourColumn, LOCATE(YourColumn, ',') + 1), 1, LOCATE(SUBSTR(YourColumn, LOCATE(YourColumn, ',') + 1), ',') - 1)
第一个 SUBSTR 正在获取字符串的右侧,因此我们只需要一个起始位置参数,第二个 SUBSTR 正在获取字符串的左侧,因此我们需要两个,即起始位置和长度 return.
我现在正在回答我自己的问题。使用 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
然后到 select 逗号分隔字符串中的第 n 个分隔值...在本例中是第 14 个
利用新函数使用此查询
SELECT SUBSTRING(C,INSTRB(C,',',1,13)+1,INSTRB(C,',',1,14)-INSTRB(C,',',1,13)-1) FROM TABLE
一个更漂亮的解决方案IMO将封装一个递归通用Table表达式(递归CTE aka RCTE) C 列中的数据生成结果 TABLE [即用户定义 Table 函数(Table UDF aka UDTF)] 然后使用标量子 select 选择有效的 record\row 数字。
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.
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 生成的行数据限制为仅所需的 numbered 标记和 numbered[=28 之前的标记=] 令牌。我无法评论 效率 对 CPU 和存储的影响,与提供的任何其他 answers 相比,但是我自己在临时存储实现和 RCTE 结果的整体速度方面的经验是积极的,尤其是当其他行 selection 限制了必须为整个查询生成的派生-table 结果的数量时请求。
UDF [and\or UDTF 和实现它们的 RCTE] 留作 reader 的练习;主要是因为我没有发布支持递归 table 表达式的系统。如果问 [例如在对此 answer] 的评论中,我可以提供 untested 代码源。
我发现 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;
我需要 select 一个逗号分隔字符串中的值,仅使用 SQL。这可能吗?
Data
A B C
1 Luigi Apple,Banana,Pineapple,,Citrus
我需要 select 具体 2nd item in column C
,在本例中是香蕉。我需要帮助。我无法创建新的 SQL 函数,我只能使用 SQL
。这是 as400
所以 SQL
有点老技术了。
更新.. 在@Sandeep 的帮助下,我们能够想出
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
我遇到了这个错误
Keyword PASSING not expected. Valid tokens: ) ,.
新更新。使用Oracle的INSTR
的UDF解决的问题如果你只想要第二项,你可以使用子字符串函数:
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
我假设我不使用 db2,因此以下语法可能不适用,但该方法有效。
在 Oracle 中,我会使用 INSTR() 和 SUBSTR(),Google 建议为 db2 使用 LOCATE() 和 SUBSTR()
使用 LOCATE 获取第一个逗号的位置,并在 SUBSTR 中使用该值获取第一个逗号后开始的 YourColumn 的末尾
SUBSTR(YourColumn, LOCATE(YourColumn, ',') + 1)
您从 "Apple,Banana,Pineapple,,Citrus" 开始,现在应该 "Banana,Pineapple,,Citrus",所以我们再次对上面的 returned 字符串使用 LOCATE 和 SUBSTR。
SUBSTR(SUBSTR(YourColumn, LOCATE(YourColumn, ',') + 1), 1, LOCATE(SUBSTR(YourColumn, LOCATE(YourColumn, ',') + 1), ',') - 1)
第一个 SUBSTR 正在获取字符串的右侧,因此我们只需要一个起始位置参数,第二个 SUBSTR 正在获取字符串的左侧,因此我们需要两个,即起始位置和长度 return.
我现在正在回答我自己的问题。使用 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
然后到 select 逗号分隔字符串中的第 n 个分隔值...在本例中是第 14 个
利用新函数使用此查询
SELECT SUBSTRING(C,INSTRB(C,',',1,13)+1,INSTRB(C,',',1,14)-INSTRB(C,',',1,13)-1) FROM TABLE
一个更漂亮的解决方案IMO将封装一个递归通用Table表达式(递归CTE aka RCTE) C 列中的数据生成结果 TABLE [即用户定义 Table 函数(Table UDF aka UDTF)] 然后使用标量子 select 选择有效的 record\row 数字。
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.
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 生成的行数据限制为仅所需的 numbered 标记和 numbered[=28 之前的标记=] 令牌。我无法评论 效率 对 CPU 和存储的影响,与提供的任何其他 answers 相比,但是我自己在临时存储实现和 RCTE 结果的整体速度方面的经验是积极的,尤其是当其他行 selection 限制了必须为整个查询生成的派生-table 结果的数量时请求。
UDF [and\or UDTF 和实现它们的 RCTE] 留作 reader 的练习;主要是因为我没有发布支持递归 table 表达式的系统。如果问 [例如在对此 answer] 的评论中,我可以提供 untested 代码源。
我发现 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;