当未定义值的顺序时,Oracle如何插入工作?

时间:2018-06-15 21:32:52

标签: oracle plsql insert-into

我遇到了一些看起来像这样的代码。我知道它将返回自动生成的id,但我不明白的是当我调用此函数时传递游标数据时,如何在列顺序不是时确定要在哪些列中插入哪些值定义

FUNCTION INSERT_ROW(DATA IN OWNER.TABLE%ROWTYPE)
    RETURN OWNER.TABLE.ID%TYPE
IS 
    l_ID OWNER.MY_TABLE.ID%TYPE;
    l_Data OWNER.MY_TABLE%ROWTYPE := DATA;
BEGIN   
    INSERT INTO OWNER.MY_TABLE
    VALUES l_Data
    RETURNING ID INTO l_ID;

我试图查找很多示例,我只是遇到了像这样定义值的那些示例        INSERT INTO my_table(val2,val3,val4)VALUES(2,3,4)返回val1       INTO val1;

3 个答案:

答案 0 :(得分:2)

代码中的insert values语句是带有括号的标准插入值子句的PL / SQL扩展。这是关于此主题的12.2手册中的页面:

https://docs.oracle.com/en/database/oracle/oracle-database/12.2/lnpls/INSERT-statement-extension.html#GUID-D81224C4-06DE-4635-A850-41D29D4A8E1B

OWNER.TABLE%ROWTYPE数据类型定义的记录具有与表相同的列并且顺序相同。您只是将数据以该格式传递给函数,并将其传递给变量,然后传递给insert语句。

答案 1 :(得分:2)

Oracle IS中表的列顺序已定义。查看ALL_TAB_COLUMNS视图 - 有一个COLUMN_ID列,用于定义表中列的顺序。如果SELECT中没有给出字段列表(即SELECT * FROM MY_TABLE),则MY_TABLE中的列将以ALL_TAB_COLUMNS.COLUMN_ID顺序返回。这与在%ROWTYPE变量中排序列的方式相同,而且没有指定字段列表的INSERT需要对字段进行排序。

答案 2 :(得分:0)

RETURNING子句的主要目的是获取派生列的值,该值是在插入过程中生成的值。通常这是从序列派生的技术主键,或者从12c开始是IDENTITY列。

例如:

create table my_table (
     val1 number generated as identity primary key
     , val2 varchar2(16)
     , val3 varchar2(16)
     , val4 date)
/

declare
    id number;
begin
    INSERT INTO my_table (val2, val3, val4) 
    VALUES ('one', 'test', sysdate) 
    RETURNING val1 INTO id;

    dbms_output.put_line('new id = ' || id);
end;
/

这就是你找到的例子在INSERT投影中指定列的原因:主键的值是自动生成的,所以我们没有必要在代码中为它赋值。

现在,您的函数在其insert语句中使用记录类型。我们不能用IDENTITY列做到这一点。这个变种......

declare
    lrec my_table%rowtype;
    id number;
begin
    lrec.val2 := 'two';
    lrec.val3 := 'test again';
    lrec.val4 :=  sysdate;

    INSERT INTO my_table
    VALUES lrec
    RETURNING val1 INTO id;

    dbms_output.put_line('new id = ' || id);
end;
/

...将投掷

  

ORA-32795:无法插入生成的始终标识列

但我们可以使用带有旧式序列的%rowtype并触发组合:

create table my_table (
     val1 number primary key
     , val2 varchar2(16)
     , val3 varchar2(16)
     , val4 date)
/

create sequence my_seq start with 42;

create or replace trigger my_trg
    before insert on my_table for each row
begin
    :new.val1 := my_seq.nextval;
end;
/

declare
    lrec my_table%rowtype;
    id number;
begin
    lrec.val1 := 1;
    lrec.val2 := 'three';
    lrec.val3 := 'test again';
    lrec.val4 :=  sysdate;

    INSERT INTO my_table
    VALUES lrec
    RETURNING val1 INTO id;

    dbms_output.put_line('new id = ' || id);
end;
/

这是a LiveSQL demo (free Oracle OTN account required, alas)。如果运行它,您将看到触发器覆盖指定的值,val1列具有序列中的值。