在SQLPLUS中更新表(使用逗号分隔列的存储过程循环)

时间:2015-02-02 20:00:23

标签: oracle stored-procedures plsql

编写存储过程时遇到一些麻烦。使用Oracle 11g

目标:我希望能够在我的表格中创建单独的行" info_table"从我的桌子" places_table"列替换名称。在places_table的列替换名下,有一个逗号分隔的字符串,其中包含多个备用名称。我想在表格#34; info_table"中为这些备用名称中的每一个创建一行。

ex of 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语句给了我&#34; SQL语句被忽略&#34;而且我不确定为什么。我已经看了一下存储过程和循环文档但是无法弄清楚我是做错了还是有错字。

有人可以帮助我吗?

提前谢谢你,

诺曼

2 个答案:

答案 0 :(得分:1)

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一旦到达姓氏就会失败。但你会明白这一点。

答案 1 :(得分:1)

这是我用来循环你要求的东西的一个小功能。您可以指定分隔符。

类型......

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