插入带有标识列的 Oracle table 时如何使用 %ROWTYPE?
How to use %ROWTYPE when inserting into Oracle table with identity column?
我有一个 Oracle 12c 数据库,其中 table 包含一个标识列:
CREATE TABLE foo (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
bar NUMBER
)
现在我想使用 PL/SQL 插入 table。由于实际上 table 有很多列,我使用 %ROWTYPE
:
DECLARE
x foo%ROWTYPE;
BEGIN
x.bar := 3;
INSERT INTO foo VALUES x;
END;
但是,它给我这个错误:
ORA-32795: cannot insert into a generated always identity column
ORA-06512: at line 5
因为它对代码的可读性和可维护性非常好,我不想停止使用%ROWTYPE
。因为我在任何情况下都不想允许除了自动生成的 ID 之外的任何东西,所以我不想解除 GENERATED ALWAYS
限制。
This 文章建议能够使用 %ROWTYPE
的唯一方法是切换到 GENERATED BY DEFAULT ON NULL
。没有其他方法可以解决这个问题吗?
您可以创建一个视图并插入其中:
CREATE OR REPLACE VIEW V_FOO AS
SELECT BAR -- all columns apart from virtual columns
FROM foo;
DECLARE
x V_FOO%ROWTYPE;
BEGIN
x.bar := 3;
INSERT INTO V_FOO VALUES x;
END;
由于您使用的是 12c,我唯一能想到的就是制作身份列 INVISIBLE
,如下面的代码。
问题是它让 %ROWTYPE
和 的 id 有点困难,但它是可行的。
当然,使用您的 table 也可能会误导其他人看不到主键!
我不认为我会这样做,但它是对你的问题的回答,这很有价值。
DROP TABLE t;
CREATE TABLE t ( id number invisible generated always as identity,
val varchar2(30));
insert into t (val) values ('A');
DECLARE
record_without_id t%rowtype;
CURSOR c_with_id IS SELECT t.id, t.* FROM t;
record_with_id c_with_id%rowtype;
BEGIN
record_without_id.val := 'C';
INSERT INTO t VALUES record_without_id;
-- If you want ID, you must select it explicitly
SELECT id, t.* INTO record_with_id FROM t WHERE rownum = 1;
DBMS_OUTPUT.PUT_LINE(record_with_id.id || ', ' || record_with_id.val);
END;
/
SELECT id, val FROM t;
我认为混合使用以前的答案 - 使用带有不可见身份列的视图 - 是完成此任务的最佳方式:
create table foo (id number generated always as identity primary key, memo varchar2 (32))
;
create or replace view fooview (id invisible, memo) as select * from foo
;
<<my>> declare
r fooview%rowtype;
id number;
begin
r.memo := 'first row';
insert into fooview values r
returning id into my.id
;
dbms_output.put_line ('inserted '||sql%rowcount||' row(s) id='||id);
end;
/
inserted 1 row(s) id=1
我有一个 Oracle 12c 数据库,其中 table 包含一个标识列:
CREATE TABLE foo (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
bar NUMBER
)
现在我想使用 PL/SQL 插入 table。由于实际上 table 有很多列,我使用 %ROWTYPE
:
DECLARE
x foo%ROWTYPE;
BEGIN
x.bar := 3;
INSERT INTO foo VALUES x;
END;
但是,它给我这个错误:
ORA-32795: cannot insert into a generated always identity column
ORA-06512: at line 5
因为它对代码的可读性和可维护性非常好,我不想停止使用%ROWTYPE
。因为我在任何情况下都不想允许除了自动生成的 ID 之外的任何东西,所以我不想解除 GENERATED ALWAYS
限制。
This 文章建议能够使用 %ROWTYPE
的唯一方法是切换到 GENERATED BY DEFAULT ON NULL
。没有其他方法可以解决这个问题吗?
您可以创建一个视图并插入其中:
CREATE OR REPLACE VIEW V_FOO AS
SELECT BAR -- all columns apart from virtual columns
FROM foo;
DECLARE
x V_FOO%ROWTYPE;
BEGIN
x.bar := 3;
INSERT INTO V_FOO VALUES x;
END;
由于您使用的是 12c,我唯一能想到的就是制作身份列 INVISIBLE
,如下面的代码。
问题是它让 %ROWTYPE
和 的 id 有点困难,但它是可行的。
当然,使用您的 table 也可能会误导其他人看不到主键!
我不认为我会这样做,但它是对你的问题的回答,这很有价值。
DROP TABLE t;
CREATE TABLE t ( id number invisible generated always as identity,
val varchar2(30));
insert into t (val) values ('A');
DECLARE
record_without_id t%rowtype;
CURSOR c_with_id IS SELECT t.id, t.* FROM t;
record_with_id c_with_id%rowtype;
BEGIN
record_without_id.val := 'C';
INSERT INTO t VALUES record_without_id;
-- If you want ID, you must select it explicitly
SELECT id, t.* INTO record_with_id FROM t WHERE rownum = 1;
DBMS_OUTPUT.PUT_LINE(record_with_id.id || ', ' || record_with_id.val);
END;
/
SELECT id, val FROM t;
我认为混合使用以前的答案 - 使用带有不可见身份列的视图 - 是完成此任务的最佳方式:
create table foo (id number generated always as identity primary key, memo varchar2 (32))
;
create or replace view fooview (id invisible, memo) as select * from foo
;
<<my>> declare
r fooview%rowtype;
id number;
begin
r.memo := 'first row';
insert into fooview values r
returning id into my.id
;
dbms_output.put_line ('inserted '||sql%rowcount||' row(s) id='||id);
end;
/
inserted 1 row(s) id=1