未定义值顺序时 Oracle Insert Into 如何工作?
How does Oracle Insert Into work when order of values is not defined?
我遇到了一些看起来像这样的代码。我知道它将 return 自动生成的 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;
我试图查找许多示例,但我只遇到过按如下顺序定义值的示例
插入 my_table (val2, val3, val4) 值 (2, 3, 4) 返回 val1
INTO val1;
您代码中的插入值语句是对带括号的标准插入值子句的 PL/SQL 扩展。这是 12.2 手册中关于此主题的页面:
OWNER.TABLE%ROWTYPE 数据类型定义了与 table 具有相同列且顺序相同的记录。您只是将数据以该格式传递给函数并将其传递给变量,然后传递给插入语句。
Oracle 中 table 中列的顺序已定义。查看 ALL_TAB_COLUMNS 视图 - 有一个 COLUMN_ID 列定义了 table 中列的顺序。如果 SELECT 中未给出字段列表(即 SELECT * FROM MY_TABLE),MY_TABLE 中的列将按 ALL_TAB_COLUMNS.COLUMN_ID 顺序返回。这也是在 %ROWTYPE 变量中对列进行排序的方式,也是没有指定字段列表的 INSERT 期望对字段进行排序的方式。
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 投影中指定列的原因:主键的值是自动生成的,因此我们没有必要在代码中为其赋值。
现在您的函数在其插入语句中使用记录类型。我们不能用 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: cannot insert into a generated always identity column
但我们可以使用 %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
列具有来自序列的值。
我遇到了一些看起来像这样的代码。我知道它将 return 自动生成的 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;
我试图查找许多示例,但我只遇到过按如下顺序定义值的示例 插入 my_table (val2, val3, val4) 值 (2, 3, 4) 返回 val1 INTO val1;
您代码中的插入值语句是对带括号的标准插入值子句的 PL/SQL 扩展。这是 12.2 手册中关于此主题的页面:
OWNER.TABLE%ROWTYPE 数据类型定义了与 table 具有相同列且顺序相同的记录。您只是将数据以该格式传递给函数并将其传递给变量,然后传递给插入语句。
Oracle 中 table 中列的顺序已定义。查看 ALL_TAB_COLUMNS 视图 - 有一个 COLUMN_ID 列定义了 table 中列的顺序。如果 SELECT 中未给出字段列表(即 SELECT * FROM MY_TABLE),MY_TABLE 中的列将按 ALL_TAB_COLUMNS.COLUMN_ID 顺序返回。这也是在 %ROWTYPE 变量中对列进行排序的方式,也是没有指定字段列表的 INSERT 期望对字段进行排序的方式。
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 投影中指定列的原因:主键的值是自动生成的,因此我们没有必要在代码中为其赋值。
现在您的函数在其插入语句中使用记录类型。我们不能用 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: cannot insert into a generated always identity column
但我们可以使用 %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
列具有来自序列的值。