【问题标题】:How to use %ROWTYPE when inserting into Oracle table with identity column?插入带有标识列的 Oracle 表时如何使用 %ROWTYPE?
【发布时间】:2016-02-14 00:07:38
【问题描述】:

我有一个包含标识列的表的 Oracle 12c 数据库:

CREATE TABLE foo (
  id   NUMBER  GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  bar  NUMBER
)

现在我想使用 PL/SQL 插入表中。由于实际上该表有很多列,我使用%ROWTYPE

DECLARE
  x foo%ROWTYPE;
BEGIN
  x.bar := 3;
  INSERT INTO foo VALUES x;
END;

但是,它给了我这个错误:

ORA-32795:无法插入生成的始终标识列
ORA-06512: 在第 5 行

由于它对代码的可读性和可维护性非常好,我不想停止使用%ROWTYPE。由于我在任何情况下都不想允许除了自动生成的 ID 之外的任何内容,因此我不想解除 GENERATED ALWAYS 限制。

This 文章建议能够使用%ROWTYPE 的唯一方法是切换到GENERATED BY DEFAULT ON NULL。没有其他方法可以解决这个问题吗?

【问题讨论】:

  • GENERATED BY DEFAULT ON NULL 有什么问题?
  • @MatthewMcPeak 有人可以插入他们自己的id,这不是序列的一部分。我不想允许这样做。

标签: oracle plsql oracle12c identity-column rowtype


【解决方案1】:

由于您使用的是 12c,我唯一能想到的就是创建身份列 INVISIBLE,如下面的代码。

问题在于它使得获得%ROWTYPE with id 有点困难,但它是可行的。

当然,它也可能使其他使用您的表的人看不到主键!

我不认为我会这样做,但它回答你的问题,因为这是值得的。

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;    

【讨论】:

  • 我同意这可能会导致比它解决的问题更大的问题。但无论如何,为了完整性,我很欣赏这个想法。将所有选项摆在桌面上总是很好。
【解决方案2】:

您可以创建一个视图并在那里插入:

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;

【讨论】:

  • 感谢您的回答。聪明的解决方法!宁愿不需要任何额外的对象,所以我会在接受之前等待一段时间,看看人们有什么其他想法。
  • 好吧,如果你不喜欢创建视图,你可以循环 ALL_TAB_COLS 并使用包 DBMS_SQL 动态地做所有事情。但是,您将不得不编写大量代码,这肯定是矫枉过正。
  • 很好,Wernfried,更不用说生成的代码效率有多低了。
【解决方案3】:

我认为混合以前的答案 - 使用带有不可见标识列的视图 - 是完成此任务的最佳方式:

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

插入 1 行 id=1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-02
    • 2014-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多