我有一个包含一组名称的列。我没有设计数据库,使其在一列中包含多个值,但现在我必须提取该信息。
问题是,在一个字段中,我有多个值,如本例所示:
“杰克汤姆拉里斯坦肯尼”
所以前三个应该是一组,最右边的其他是另一组。(基本上,在列中将它们分开的唯一因素是它们之间的特定数量的空白,比如说 50 个字符。)
如何将它们拆分为纯 SQL,以便我可以得到这样的两列:
专栏1“杰克汤姆拉里”
专栏2“斯坦肯尼”
一个相当简单的答案是使用 left()、right() 和 locate() 的组合。像这样的东西(注意,为了便于阅读,我用“XXX”替换了 50 个空格):
declare global temporary table session.x(a varchar(100))
on commit preserve rows with norecovery;
insert into session.x values('Jack Tom LarryXXXStan Kenny');
select left(a,locate(a,'XXX')-1),right(a,length(a)+1-(locate(a,'XXX')+length('XXX'))) from session.x;
如果您需要一种更通用的方法从具有给定分隔符的字符串中提取第 n 个字段,有点像 PostgreSQL 中的 split_part() 函数,在 Ingres 中,您的选项将是:
使用对象管理扩展 (OME) 编写用户定义的函数。这并不完全简单,但在 Actian 社区网站的 wiki 页面中有一个很好的示例可以帮助您入门: http: //community.actian.com/wiki/OME :_User_Defined_Functions
创建行生成过程。使用起来比 OME 函数更笨重,但更容易实现。这是我对这样一个程序的尝试,虽然没有经过很好的测试,但它应该作为一个例子。您可能需要调整输入和输出字符串的宽度:
create procedure split
(
inval = varchar(200) not null,
sep = varchar(50) not null,
n = integer not null
)
result row r(x varchar(200)) =
declare tno = integer not null;
srch = integer not null;
ptr = integer not null;
resval = varchar(50);
begin
tno = 1;
srch = 1;
ptr = 1;
while (:srch <= length(:inval))
do
while (substr(:inval, :srch, length(:sep)) != :sep
and :srch <= length(:inval))
do
srch = :srch + 1;
endwhile;
if (:tno = :n)
then
resval=substr(:inval, :ptr, :srch - :ptr);
return row(:resval);
return;
endif;
srch = :srch + length(:sep);
ptr = :srch;
tno = :tno + 1;
endwhile;
return row('');
end;
select s.x from session.x t, split(t.a,'XXX',2) s;