【问题标题】:PL/SQL compilation error, can't figure out whats brokenPL/SQL 编译错误,不知道是什么坏了
【发布时间】:2015-01-20 11:17:44
【问题描述】:

所以我的 SQL 过程如下:

create or replace procedure generate_sample_dd_contracts(cnt in pls_integer)
is
begin
  for cur in (select * from (select * from tc_client cli where not exists (select 1 from tc_direct_debit dd where dd.cli_id=cli.id) order by dbms_random.value) where rownum < dbms_random.value(2,100))
    -- select query works fine and gets clients as needed
    loop
      for i in 0..cnt
        loop
          insert into tc_direct_debit (cli_id, ref_number) values (cur.id, tc_ref_num_seq.nextval);
          -- this insert also works separately from procedure, I have autoinc trigger
        end loop;
      end loop;
  commit;
end;
/
begin
  generate_sample_dd_contracts(3);
end;

第一个for循环选择查询结果

当我运行程序时,tc_direct_debit ID 得到更新(into 子句),但表中没有数据。

还有报错:

PROCEDURE GENERATE_SAMPLE_DD_CONTRACTS compiled
Error starting at line 19 in command:
begin
  generate_sample_dd_contracts(3);
end;
Error report:
ORA-00001: unique constraint (T.U_DIRECT_DEBIT_CLI_ID) violated
ORA-06512: at "T.GENERATE_SAMPLE_DD_CONTRACTS", line 9
ORA-06512: at line 2
00001. 00000 -  "unique constraint (%s.%s) violated"
*Cause:    An UPDATE or INSERT statement attempted to insert a duplicate key.
           For Trusted Oracle configured in DBMS MAC mode, you may see
           this message if a duplicate entry exists at a different level.
*Action:   Either remove the unique restriction or do not insert the key.

据我了解,insert 尝试添加一个已经存在但 tc_direct_debit 为空的 cli_id(已将其截断多次以确保)。

tc_direct_debit 表

`CREATE TABLE TC_DIRECT_DEBIT
(ID NUMBER NOT NULL
, CLI_ID NUMBER NOT NULL 
, REF_NUMBER VARCHAR2(20) NOT NULL 
, CONSTRAINT TC_DIRECT_DEBIT_PK PRIMARY KEY (ID)
, CONSTRAINT U_DIRECT_DEBIT_CLI_ID UNIQUE (CLI_ID)
, CONSTRAINT TC_DIRECT_DEBIT_CLI_FK FOREIGN KEY (CLI_ID) REFERENCES TC_CLIENT (ID)
);`

【问题讨论】:

  • tc_direct_debit 是否包含cli_id 作为主键?
  • 不,没有,添加到帖子中。
  • 但它有独特的约束CONSTRAINT U_DIRECT_DEBIT_CLI_ID UNIQUE (CLI_ID)
  • 这个额外的循环是什么? for i in 0..cnt 您正在尝试为 cnt 次插入相同的 cli_id
  • 这意味着为每个客户添加 cnt 不同的直接借记

标签: sql oracle plsql oracle-sqldeveloper


【解决方案1】:

为光标中的每一行插入四次(从 0 到 3)。

我认为你想做的代码是:

create or replace procedure generate_sample_dd_contracts(cnt in pls_integer)
is
declare 
i number;
begin
i:=0;
  for cur in (select * from (select * from tc_client cli where not exists (select 1 from tc_direct_debit dd where dd.cli_id=cli.id) order by dbms_random.value) where rownum < dbms_random.value(2,100))
    loop
      i:=i+1;
      exit when i > cnt;
      insert into tc_direct_debit (cli_id, ref_number) values (cur.id, tc_ref_num_seq.nextval);
    end loop;
  commit;
end;
/

或者更好,只是改变光标代码:

create or replace procedure generate_sample_dd_contracts(cnt in pls_integer)
is
begin
  for cur in (select * from (select * from tc_client cli where not exists (select 1 from tc_direct_debit dd where dd.cli_id=cli.id) order by dbms_random.value) where rownum <= cnt)
    loop
      insert into tc_direct_debit (cli_id, ref_number) values (cur.id, tc_ref_num_seq.nextval);
    end loop;
  commit;
end;
/

【讨论】:

  • 这也是对任务的一种可能解释。我实际上是这样做的,因为我不允许更改表定义。谢谢!
【解决方案2】:

CLI_ID 似乎被称为unique key,这意味着不惜任何代价不接受副本。 wherears 中的程序line 9 已循环插入

 for i in 0..cnt
   loop
     insert into tc_direct_debit (cli_id, ref_number) values (cur.id, tc_ref_num_seq.nextval);
   -- this insert also works separately from procedure, I have autoinc trigger
 end loop;

删除唯一约束 U_DIRECT_DEBIT_CLI_ID 将解决您的问题

【讨论】:

  • 谢谢!我正在准备 SQL 考试,这是一项任务的一部分,该任务表明该程序应该为已经没有的随机客户生成 cnt 直接借记合同,但任务语句似乎与 TC_DIRECT_DEBIT 表定义冲突.
猜你喜欢
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-29
  • 1970-01-01
相关资源
最近更新 更多