在 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;
/