在 SQLPLUS 中更新 table(带逗号分隔列的存储过程循环)
Updating table in SQLPLUS (Stored Procedure Loop with Comma Delimited Column)
在编写我的存储过程时遇到一些问题。使用 Oracle 11g
目标:我希望能够在 table "info_table" 和 table "places_table" 中使用列备用名称创建单独的行。在来自 places_table 的 alternatenames 列下,有一个包含多个备用名称的逗号分隔字符串。我想为 table "info_table".
中的每个替代名称创建一行
alternatenames 列字符串的示例:
Beijing,Beijingzi,Pei-ching-tzu
我希望达到的目标
ID Name
100000000 Beijing
100000001 Beijingzi
100000002 Pei-ching-tzu
目前我的代码是这样的:
CREATE TABLE INFO_TABLE
(
INFOID NUMBER PRIMARY KEY,
NAME VARCHAR2(500),
LANGUAGE VARCHAR2(40),
STATUS VARCHAR2(50),
COUNTRY_CODE CHAR (10),
COUNTRY_CODE_2 CHAR (10),
GID CHAR(10),
SUPPLIERID CHAR(10),
LAST_MODIFIED CHAR(50)
);
CREATE SEQUENCE INFO_COUNTER
START WITH 100000000;
CREATE PROCEDURE LOAD_ALTERNATE_NAMES(ALTERNATENAMES_COLUMN VARCHAR2)
AS
COMMA_FINDER NUMBER := 1;
BEGIN
IF ALTERNATENAMES_COLUMN IS NOT NULL
THEN
<<SEPARATE_ALTERNATENAMES>> WHILE COMMA_FINDER!=0 LOOP
INSERT INTO INFO_TABLE
(INFOID, NAME, LANGUAGE, STATUS, COUNTRY_CODE, COUNTRY_CODE_2, GID, SUPPLIERID, LAST_MODIFIED)
VALUES
(INFO_COUNTER, SUBSTR(ALTERNATENAMES_COLUMN, INSTR(P.ALTERNATENAMES, ',', COMMA_FINDER+1)), NULL, 'ALTERNATE', P.COUNTRY_CODE, P.COUNTRY_CODE_2, P.GID, NULL, P.LASTMODIFIED)
FROM INFO_TABLE I, PLACES_TABLE P;
COMMA_FINDER := INSTR(ALTERNATENAMES, ',', COMMA_FINDER);
END LOOP SEPARATE_ALTERNATENAMES;
COMMA_FINDER:=1;
ENDIF;
END
/
LOAD_ALTERNATE_NAMES(SELECT ALTERNATENAMES FROM PLACES_TABLE);
目前的问题是我循环中的 INSERT 语句给了我 "SQL Statement Ignored",我不确定为什么。我查看了存储过程和循环文档,但无法确定是我做错了什么还是有错字。
有人可以帮我吗?
提前谢谢你,
诺曼
INSERT 语句的形式为:
INSERT INTO table (...) VALUES (...)
或:
INSERT INTO table (...) SELECT ... FROM ...
这就是 Oracle 发出错误消息的原因。
但还有更多。您将 ALTERNATENAMES 字符串值传递给存储过程,但需要来自 PLACES_TABLE 的更多数据。此外,Oracle 不支持这样的存储过程调用:
LOAD_ALTERNATE_NAMES(SELECT ALTERNATENAMES FROM PLACES_TABLE);
所以我建议你创建一个没有参数的存储过程:
CREATE PROCEDURE LOAD_ALTERNATE_NAMES
AS
COMMA_FINDER NUMBER;
BEGIN
FOR REC IN (
SELECT * FROM PLACES_TABLE WHERE ALTERNATENAMES IS NOT NULL
) LOOP
COMMA_FINDER NUMBER := 1;
<<SEPARATE_ALTERNATENAMES>> WHILE COMMA_FINDER!=0 LOOP
INSERT INTO INFO_TABLE
(INFOID, NAME, LANGUAGE, STATUS, COUNTRY_CODE, COUNTRY_CODE_2, GID, SUPPLIERID, LAST_MODIFIED)
VALUES
(INFO_COUNTER.NEXTVAL, SUBSTR(REC.ALTERNATENAMES, INSTR(REC.ALTERNATENAMES, ',', COMMA_FINDER+1)), NULL, 'ALTERNATE', REC.COUNTRY_CODE, REC.COUNTRY_CODE_2, REC.GID, NULL, REC.LASTMODIFIED);
COMMA_FINDER := INSTR(REC.ALTERNATENAMES, ',', COMMA_FINDER);
END LOOP SEPARATE_ALTERNATENAMES;
END LOOP;
END
/
希望对您有所帮助。我还没有测试过,我担心 SUBSTR 一旦到达姓氏就会失败。但你会明白的。
这是一个小函数,我用它来循环你所要求的东西。您可以指定分隔符。
类型...
type split_array is table of varchar2(32767) index by binary_integer;
函数...
function split(string_in varchar2, delim_in varchar2) return split_array is
i number :=0;
pos number :=0;
lv_str varchar2(32767) := string_in;
strings split_array;
dl number;
begin
-- determine first chuck of string
pos := instr(lv_str,delim_in,1,1);
-- get the length of the delimiter
dl := length(delim_in);
if (pos = 0) then --then we assume there is only 1 items in the list. so we just add the delimiter to the end which would make the pos length+1;
strings(1) := lv_str;
end if;
-- while there are chunks left, loop
while ( pos != 0) loop
-- increment counter
i := i + 1;
-- create array element for chuck of string
strings(i) := substr(lv_str,1,pos-1);
-- remove chunk from string
lv_str := substr(lv_str,pos+dl,length(lv_str));
-- determine next chunk
pos := instr(lv_str,delim_in,1,1);
-- no last chunk, add to array
if pos = 0 then
strings(i+1) := lv_str;
end if;
end loop;
-- return array
return strings;
end split;
如何使用它...
declare
/* alternatenames varchar2(32767) := 'one,two,three,four'; */
nameArray split_array;
begin
for c1 in ( select alternatenames from yourTable where alternatenames is not null )
loop
nameArray := split(c1.alternatenames,',');
for i in 1..nameArray.count loop
/* dbms_output.put_line(nameArray(i)); */
insert into yourTable ( yourColumn ) values ( nameArray(i) );
end loop;
end loop;
end;
/
在编写我的存储过程时遇到一些问题。使用 Oracle 11g
目标:我希望能够在 table "info_table" 和 table "places_table" 中使用列备用名称创建单独的行。在来自 places_table 的 alternatenames 列下,有一个包含多个备用名称的逗号分隔字符串。我想为 table "info_table".
中的每个替代名称创建一行alternatenames 列字符串的示例:
Beijing,Beijingzi,Pei-ching-tzu
我希望达到的目标
ID Name
100000000 Beijing
100000001 Beijingzi
100000002 Pei-ching-tzu
目前我的代码是这样的:
CREATE TABLE INFO_TABLE
(
INFOID NUMBER PRIMARY KEY,
NAME VARCHAR2(500),
LANGUAGE VARCHAR2(40),
STATUS VARCHAR2(50),
COUNTRY_CODE CHAR (10),
COUNTRY_CODE_2 CHAR (10),
GID CHAR(10),
SUPPLIERID CHAR(10),
LAST_MODIFIED CHAR(50)
);
CREATE SEQUENCE INFO_COUNTER
START WITH 100000000;
CREATE PROCEDURE LOAD_ALTERNATE_NAMES(ALTERNATENAMES_COLUMN VARCHAR2)
AS
COMMA_FINDER NUMBER := 1;
BEGIN
IF ALTERNATENAMES_COLUMN IS NOT NULL
THEN
<<SEPARATE_ALTERNATENAMES>> WHILE COMMA_FINDER!=0 LOOP
INSERT INTO INFO_TABLE
(INFOID, NAME, LANGUAGE, STATUS, COUNTRY_CODE, COUNTRY_CODE_2, GID, SUPPLIERID, LAST_MODIFIED)
VALUES
(INFO_COUNTER, SUBSTR(ALTERNATENAMES_COLUMN, INSTR(P.ALTERNATENAMES, ',', COMMA_FINDER+1)), NULL, 'ALTERNATE', P.COUNTRY_CODE, P.COUNTRY_CODE_2, P.GID, NULL, P.LASTMODIFIED)
FROM INFO_TABLE I, PLACES_TABLE P;
COMMA_FINDER := INSTR(ALTERNATENAMES, ',', COMMA_FINDER);
END LOOP SEPARATE_ALTERNATENAMES;
COMMA_FINDER:=1;
ENDIF;
END
/
LOAD_ALTERNATE_NAMES(SELECT ALTERNATENAMES FROM PLACES_TABLE);
目前的问题是我循环中的 INSERT 语句给了我 "SQL Statement Ignored",我不确定为什么。我查看了存储过程和循环文档,但无法确定是我做错了什么还是有错字。
有人可以帮我吗?
提前谢谢你,
诺曼
INSERT 语句的形式为:
INSERT INTO table (...) VALUES (...)
或:
INSERT INTO table (...) SELECT ... FROM ...
这就是 Oracle 发出错误消息的原因。
但还有更多。您将 ALTERNATENAMES 字符串值传递给存储过程,但需要来自 PLACES_TABLE 的更多数据。此外,Oracle 不支持这样的存储过程调用:
LOAD_ALTERNATE_NAMES(SELECT ALTERNATENAMES FROM PLACES_TABLE);
所以我建议你创建一个没有参数的存储过程:
CREATE PROCEDURE LOAD_ALTERNATE_NAMES
AS
COMMA_FINDER NUMBER;
BEGIN
FOR REC IN (
SELECT * FROM PLACES_TABLE WHERE ALTERNATENAMES IS NOT NULL
) LOOP
COMMA_FINDER NUMBER := 1;
<<SEPARATE_ALTERNATENAMES>> WHILE COMMA_FINDER!=0 LOOP
INSERT INTO INFO_TABLE
(INFOID, NAME, LANGUAGE, STATUS, COUNTRY_CODE, COUNTRY_CODE_2, GID, SUPPLIERID, LAST_MODIFIED)
VALUES
(INFO_COUNTER.NEXTVAL, SUBSTR(REC.ALTERNATENAMES, INSTR(REC.ALTERNATENAMES, ',', COMMA_FINDER+1)), NULL, 'ALTERNATE', REC.COUNTRY_CODE, REC.COUNTRY_CODE_2, REC.GID, NULL, REC.LASTMODIFIED);
COMMA_FINDER := INSTR(REC.ALTERNATENAMES, ',', COMMA_FINDER);
END LOOP SEPARATE_ALTERNATENAMES;
END LOOP;
END
/
希望对您有所帮助。我还没有测试过,我担心 SUBSTR 一旦到达姓氏就会失败。但你会明白的。
这是一个小函数,我用它来循环你所要求的东西。您可以指定分隔符。
类型...
type split_array is table of varchar2(32767) index by binary_integer;
函数...
function split(string_in varchar2, delim_in varchar2) return split_array is
i number :=0;
pos number :=0;
lv_str varchar2(32767) := string_in;
strings split_array;
dl number;
begin
-- determine first chuck of string
pos := instr(lv_str,delim_in,1,1);
-- get the length of the delimiter
dl := length(delim_in);
if (pos = 0) then --then we assume there is only 1 items in the list. so we just add the delimiter to the end which would make the pos length+1;
strings(1) := lv_str;
end if;
-- while there are chunks left, loop
while ( pos != 0) loop
-- increment counter
i := i + 1;
-- create array element for chuck of string
strings(i) := substr(lv_str,1,pos-1);
-- remove chunk from string
lv_str := substr(lv_str,pos+dl,length(lv_str));
-- determine next chunk
pos := instr(lv_str,delim_in,1,1);
-- no last chunk, add to array
if pos = 0 then
strings(i+1) := lv_str;
end if;
end loop;
-- return array
return strings;
end split;
如何使用它...
declare
/* alternatenames varchar2(32767) := 'one,two,three,four'; */
nameArray split_array;
begin
for c1 in ( select alternatenames from yourTable where alternatenames is not null )
loop
nameArray := split(c1.alternatenames,',');
for i in 1..nameArray.count loop
/* dbms_output.put_line(nameArray(i)); */
insert into yourTable ( yourColumn ) values ( nameArray(i) );
end loop;
end loop;
end;
/