在 Oracle PL/SQL 中使用循环动态连接字符串
Dynamically concatenating strings using a loop in Oracle PL/SQL
我一直在尝试将 table 的“地址”字段标准化为 40 万行。问题是,这个字段是一个自由格式字段,这意味着用户(在注册后)可以输入他们想要的任何内容。我已经设法将这个地址字段分成 14 个,地址行的每个单词都按顺序排列。
现在我需要将其中一些字段连接回不同的字段,例如:
- 街道名称
- 门牌号
我希望它能像抓住前 3 个字段一样简单,并将街道名称和第 4 个字段称为门牌号,但由于街道名称长度不同,带有“门牌号”的字段通常是字段#4、#5,很少有#3 或#6。
我已经想到了一种在这种情况下可行的方法,它将在一个循环中连接这些字段,并使用第一个数字是数字的字段的第一次出现作为断点。(由于一些房屋编号为“10C”、“1A”、“1B”等)
由于不太擅长PL/SQL,我不知道如何把这个想法变成代码。
到目前为止我所做的就是编写一个函数来检查字符串是否以数字开头,因此它可以在 IF 函数中使用。
如何使用 PL/SQL 动态“遍历”循环中的字段?我会使用数组吗?有可能吗?
编辑:
此地址字段包含的内容示例(葡萄牙语):
Avenida Doutor Theomário Pinto da Costa 450 Condominio Renaissance, rua 1, casa 1
Rua Álvaro Peres Filho 60 Casa azul em frente ao orelhão
Travessa Delegado Zé Lima 61 antiga Praça Rio Branco
Rua Finlândia 28 Qd 111
Alameda Áustria 107 Condomínio Jardim Europa I
数据中有一个清晰的模式,这让我相信这个地址数据是以分段格式收集的,然后连接成一个 table 字段。我需要做的是反过来,基本上。
模式是:
Avenida(1) Doutor Theomário Pinto da Costa (2) 450(3) Condominio Renaissance, rua 1, casa 1(4)
1 = 街道类型(大道、街道等)
2 = 街道名称
3 = 门牌号
4 = 参考(通常用于帮助指路,此字段通常是设计开放的。楼层、建筑物和公寓名称等内容放在此处。)
从上面的示例中可以看出,街道的名称长度通常大相径庭,因此无法将特定数量的字段设置为街道名称。
可能的解决方案:
Declare
/* Dynamically concatenating strings using a loop in Oracle PL/SQL */
--
type tyArray_parsed
is table of varchar2(2000)
index by binary_integer;
--
arAddress_parsed tyArray_parsed;
--
cnuSTREET_TYPE constant integer:=1;
cnuSTREET_NAME constant integer:=2;
cnuHOUSE_NUMBER constant integer:=3;
cnuREFERENCE constant integer:=4;
--
Procedure print(p_isbTexto varchar2)
is
nuIzq_print integer;
nuDer_print integer;
Begin
nuDer_print:=0;
Loop
nuIzq_print:=nuDer_print+1;
nuDer_print:=instr(p_isbTexto,chr(10),nuIzq_print);
exit when nvl(nuDer_print,0)=0;
dbms_output.put_line(substr(p_isbTexto, nuIzq_print, nuDer_print-nuIzq_print));
End loop;
dbms_output.put_line(substr(p_isbTexto, nuIzq_print));
End print;
--
procedure pAddress_split(isbAddress_string varchar2,
oarAddress_parsed out tyArray_parsed
)
is
type tyArray_string
is table of varchar2(2000)
index by binary_integer;
--
arFields tyArray_string;
nuLeft_pos integer;
nuRight_pos integer;
nuMy_number number;
blIs_number boolean;
nuStep integer;
Begin
print('---------------------------------------');
print('isbAddress_string=['||isbAddress_string||']');
--
nuRight_pos:=0;
Loop
nuLeft_pos:=nuRight_pos+1;
nuRight_pos:=instr(isbAddress_string,' ',nuLeft_pos);
exit when nvl(nuRight_pos,0)=0;
arFields(arFields.COUNT+1):=substr(isbAddress_string,
nuLeft_pos,
nuRight_pos-nuLeft_pos
);
End loop;
arFields(arFields.COUNT+1):=substr(isbAddress_string,
nuLeft_pos
);
print('arFields.COUNT='||arFields.COUNT);
--
For nuI in arFields.FIRST..arFields.LAST loop
print(lpad(nuI,4)||'['||arFields(nui)||']');
End loop;
--
nuStep:=cnuSTREET_TYPE;
For nuI in arFields.FIRST..arFields.LAST loop
if nuStep=cnuSTREET_TYPE then
oarAddress_parsed(cnuSTREET_TYPE):=arFields(nui);
nuStep:=cnuSTREET_NAME;
Elsif nuStep=cnuSTREET_NAME then
blIs_number:=false;
Begin
nuMy_number:=to_number(arFields(nui));
blIs_number:=true;
Exception
when others then
blIs_number:=false;
End;
if blIs_number then
oarAddress_parsed(cnuHOUSE_NUMBER):=arFields(nui);
nuStep:=cnuREFERENCE;
Else
if not(oarAddress_parsed.exists(cnuSTREET_NAME)) then
oarAddress_parsed(cnuSTREET_NAME):=arFields(nui);
Else
oarAddress_parsed(cnuSTREET_NAME):=oarAddress_parsed(cnuSTREET_NAME)||' '||arFields(nui);
End if;
End if;
Elsif nuStep=cnuREFERENCE then
if not(oarAddress_parsed.exists(cnuREFERENCE)) then
oarAddress_parsed(cnuREFERENCE):=arFields(nui);
Else
if arFields(nui)=',' then
oarAddress_parsed(cnuREFERENCE):=oarAddress_parsed(cnuREFERENCE)||arFields(nui);
Else
oarAddress_parsed(cnuREFERENCE):=oarAddress_parsed(cnuREFERENCE)||' '||arFields(nui);
end if;
End if;
End if;
End loop;
--
for nuI in oarAddress_parsed.FIRST..oarAddress_parsed.LAST loop
print(lpad(nuI,2)||'|['||oarAddress_parsed(nui)||']');
End loop;
End pAddress_split;
Begin
dbms_application_info.set_module('Split','START-'||to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'));
--
pAddress_split('Avenida Doutor Theomário Pinto da Costa 450 Condominio Renaissance, rua 1, casa 1',arAddress_parsed);
pAddress_split('Rua Álvaro Peres Filho 60 Casa azul em frente ao orelhão',arAddress_parsed);
pAddress_split('Travessa Delegado Zé Lima 61 antiga Praça Rio Branco',arAddress_parsed);
pAddress_split('Rua Finlândia 28 Qd 111',arAddress_parsed);
pAddress_split('Alameda Áustria 107 Condomínio Jardim Europa I',arAddress_parsed);
--
--
dbms_application_info.set_module('Split','END-'||to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'));
End;
/
答案:
---------------------------------------
isbAddress_string=[Avenida Doutor Theomário Pinto da Costa 450 Condominio Renaissance, rua 1, casa 1]
arFields.COUNT=13
1[Avenida]
2[Doutor]
3[Theomário]
4[Pinto]
5[da]
6[Costa]
7[450]
8[Condominio]
9[Renaissance,]
10[rua]
11[1,]
12[casa]
13[1]
1|[Avenida]
2|[Doutor Theomário Pinto da Costa]
3|[450]
4|[Condominio Renaissance, rua 1, casa 1]
---------------------------------------
isbAddress_string=[Rua Álvaro Peres Filho 60 Casa azul em frente ao orelhão]
arFields.COUNT=11
1[Rua]
2[Álvaro]
3[Peres]
4[Filho]
5[60]
6[Casa]
7[azul]
8[em]
9[frente]
10[ao]
11[orelhão]
1|[Rua]
2|[Álvaro Peres Filho]
3|[60]
4|[Casa azul em frente ao orelhão]
---------------------------------------
isbAddress_string=[Travessa Delegado Zé Lima 61 antiga Praça Rio Branco]
arFields.COUNT=9
1[Travessa]
2[Delegado]
3[Zé]
4[Lima]
5[61]
6[antiga]
7[Praça]
8[Rio]
9[Branco]
1|[Travessa]
2|[Delegado Zé Lima]
3|[61]
4|[antiga Praça Rio Branco]
---------------------------------------
isbAddress_string=[Rua Finlândia 28 Qd 111]
arFields.COUNT=5
1[Rua]
2[Finlândia]
3[28]
4[Qd]
5[111]
1|[Rua]
2|[Finlândia]
3|[28]
4|[Qd 111]
---------------------------------------
isbAddress_string=[Alameda Áustria 107 Condomínio Jardim Europa I]
arFields.COUNT=7
1[Alameda]
2[Áustria]
3[107]
4[Condomínio]
5[Jardim]
6[Europa]
7[I]
1|[Alameda]
2|[Áustria]
3|[107]
4|[Condomínio Jardim Europa I]
我一直在尝试将 table 的“地址”字段标准化为 40 万行。问题是,这个字段是一个自由格式字段,这意味着用户(在注册后)可以输入他们想要的任何内容。我已经设法将这个地址字段分成 14 个,地址行的每个单词都按顺序排列。
现在我需要将其中一些字段连接回不同的字段,例如:
- 街道名称
- 门牌号
我希望它能像抓住前 3 个字段一样简单,并将街道名称和第 4 个字段称为门牌号,但由于街道名称长度不同,带有“门牌号”的字段通常是字段#4、#5,很少有#3 或#6。
我已经想到了一种在这种情况下可行的方法,它将在一个循环中连接这些字段,并使用第一个数字是数字的字段的第一次出现作为断点。(由于一些房屋编号为“10C”、“1A”、“1B”等)
由于不太擅长PL/SQL,我不知道如何把这个想法变成代码。
到目前为止我所做的就是编写一个函数来检查字符串是否以数字开头,因此它可以在 IF 函数中使用。
如何使用 PL/SQL 动态“遍历”循环中的字段?我会使用数组吗?有可能吗?
编辑: 此地址字段包含的内容示例(葡萄牙语):
Avenida Doutor Theomário Pinto da Costa 450 Condominio Renaissance, rua 1, casa 1
Rua Álvaro Peres Filho 60 Casa azul em frente ao orelhão
Travessa Delegado Zé Lima 61 antiga Praça Rio Branco
Rua Finlândia 28 Qd 111
Alameda Áustria 107 Condomínio Jardim Europa I
数据中有一个清晰的模式,这让我相信这个地址数据是以分段格式收集的,然后连接成一个 table 字段。我需要做的是反过来,基本上。
模式是:
Avenida(1) Doutor Theomário Pinto da Costa (2) 450(3) Condominio Renaissance, rua 1, casa 1(4)
1 = 街道类型(大道、街道等)
2 = 街道名称
3 = 门牌号
4 = 参考(通常用于帮助指路,此字段通常是设计开放的。楼层、建筑物和公寓名称等内容放在此处。)
从上面的示例中可以看出,街道的名称长度通常大相径庭,因此无法将特定数量的字段设置为街道名称。
可能的解决方案:
Declare
/* Dynamically concatenating strings using a loop in Oracle PL/SQL */
--
type tyArray_parsed
is table of varchar2(2000)
index by binary_integer;
--
arAddress_parsed tyArray_parsed;
--
cnuSTREET_TYPE constant integer:=1;
cnuSTREET_NAME constant integer:=2;
cnuHOUSE_NUMBER constant integer:=3;
cnuREFERENCE constant integer:=4;
--
Procedure print(p_isbTexto varchar2)
is
nuIzq_print integer;
nuDer_print integer;
Begin
nuDer_print:=0;
Loop
nuIzq_print:=nuDer_print+1;
nuDer_print:=instr(p_isbTexto,chr(10),nuIzq_print);
exit when nvl(nuDer_print,0)=0;
dbms_output.put_line(substr(p_isbTexto, nuIzq_print, nuDer_print-nuIzq_print));
End loop;
dbms_output.put_line(substr(p_isbTexto, nuIzq_print));
End print;
--
procedure pAddress_split(isbAddress_string varchar2,
oarAddress_parsed out tyArray_parsed
)
is
type tyArray_string
is table of varchar2(2000)
index by binary_integer;
--
arFields tyArray_string;
nuLeft_pos integer;
nuRight_pos integer;
nuMy_number number;
blIs_number boolean;
nuStep integer;
Begin
print('---------------------------------------');
print('isbAddress_string=['||isbAddress_string||']');
--
nuRight_pos:=0;
Loop
nuLeft_pos:=nuRight_pos+1;
nuRight_pos:=instr(isbAddress_string,' ',nuLeft_pos);
exit when nvl(nuRight_pos,0)=0;
arFields(arFields.COUNT+1):=substr(isbAddress_string,
nuLeft_pos,
nuRight_pos-nuLeft_pos
);
End loop;
arFields(arFields.COUNT+1):=substr(isbAddress_string,
nuLeft_pos
);
print('arFields.COUNT='||arFields.COUNT);
--
For nuI in arFields.FIRST..arFields.LAST loop
print(lpad(nuI,4)||'['||arFields(nui)||']');
End loop;
--
nuStep:=cnuSTREET_TYPE;
For nuI in arFields.FIRST..arFields.LAST loop
if nuStep=cnuSTREET_TYPE then
oarAddress_parsed(cnuSTREET_TYPE):=arFields(nui);
nuStep:=cnuSTREET_NAME;
Elsif nuStep=cnuSTREET_NAME then
blIs_number:=false;
Begin
nuMy_number:=to_number(arFields(nui));
blIs_number:=true;
Exception
when others then
blIs_number:=false;
End;
if blIs_number then
oarAddress_parsed(cnuHOUSE_NUMBER):=arFields(nui);
nuStep:=cnuREFERENCE;
Else
if not(oarAddress_parsed.exists(cnuSTREET_NAME)) then
oarAddress_parsed(cnuSTREET_NAME):=arFields(nui);
Else
oarAddress_parsed(cnuSTREET_NAME):=oarAddress_parsed(cnuSTREET_NAME)||' '||arFields(nui);
End if;
End if;
Elsif nuStep=cnuREFERENCE then
if not(oarAddress_parsed.exists(cnuREFERENCE)) then
oarAddress_parsed(cnuREFERENCE):=arFields(nui);
Else
if arFields(nui)=',' then
oarAddress_parsed(cnuREFERENCE):=oarAddress_parsed(cnuREFERENCE)||arFields(nui);
Else
oarAddress_parsed(cnuREFERENCE):=oarAddress_parsed(cnuREFERENCE)||' '||arFields(nui);
end if;
End if;
End if;
End loop;
--
for nuI in oarAddress_parsed.FIRST..oarAddress_parsed.LAST loop
print(lpad(nuI,2)||'|['||oarAddress_parsed(nui)||']');
End loop;
End pAddress_split;
Begin
dbms_application_info.set_module('Split','START-'||to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'));
--
pAddress_split('Avenida Doutor Theomário Pinto da Costa 450 Condominio Renaissance, rua 1, casa 1',arAddress_parsed);
pAddress_split('Rua Álvaro Peres Filho 60 Casa azul em frente ao orelhão',arAddress_parsed);
pAddress_split('Travessa Delegado Zé Lima 61 antiga Praça Rio Branco',arAddress_parsed);
pAddress_split('Rua Finlândia 28 Qd 111',arAddress_parsed);
pAddress_split('Alameda Áustria 107 Condomínio Jardim Europa I',arAddress_parsed);
--
--
dbms_application_info.set_module('Split','END-'||to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'));
End;
/
答案:
---------------------------------------
isbAddress_string=[Avenida Doutor Theomário Pinto da Costa 450 Condominio Renaissance, rua 1, casa 1]
arFields.COUNT=13
1[Avenida]
2[Doutor]
3[Theomário]
4[Pinto]
5[da]
6[Costa]
7[450]
8[Condominio]
9[Renaissance,]
10[rua]
11[1,]
12[casa]
13[1]
1|[Avenida]
2|[Doutor Theomário Pinto da Costa]
3|[450]
4|[Condominio Renaissance, rua 1, casa 1]
---------------------------------------
isbAddress_string=[Rua Álvaro Peres Filho 60 Casa azul em frente ao orelhão]
arFields.COUNT=11
1[Rua]
2[Álvaro]
3[Peres]
4[Filho]
5[60]
6[Casa]
7[azul]
8[em]
9[frente]
10[ao]
11[orelhão]
1|[Rua]
2|[Álvaro Peres Filho]
3|[60]
4|[Casa azul em frente ao orelhão]
---------------------------------------
isbAddress_string=[Travessa Delegado Zé Lima 61 antiga Praça Rio Branco]
arFields.COUNT=9
1[Travessa]
2[Delegado]
3[Zé]
4[Lima]
5[61]
6[antiga]
7[Praça]
8[Rio]
9[Branco]
1|[Travessa]
2|[Delegado Zé Lima]
3|[61]
4|[antiga Praça Rio Branco]
---------------------------------------
isbAddress_string=[Rua Finlândia 28 Qd 111]
arFields.COUNT=5
1[Rua]
2[Finlândia]
3[28]
4[Qd]
5[111]
1|[Rua]
2|[Finlândia]
3|[28]
4|[Qd 111]
---------------------------------------
isbAddress_string=[Alameda Áustria 107 Condomínio Jardim Europa I]
arFields.COUNT=7
1[Alameda]
2[Áustria]
3[107]
4[Condomínio]
5[Jardim]
6[Europa]
7[I]
1|[Alameda]
2|[Áustria]
3|[107]
4|[Condomínio Jardim Europa I]