Reputation: 1005
So my SQL procedure is following:
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;
First for loops select query result
Also when I run the procedure tc_direct_debit ID gets updated (into clause) but no data appears in table.
And the error report:
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.
From this I understand that insert tries to add a cli_id that already exists but tc_direct_debit is empty (have truncated it many times to be sure).
tc_direct_debit table
`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)
);`
Upvotes: 1
Views: 118
Reputation: 17643
For every line in the cursor you insert it four times (from 0 to three).
A code doing what I think you want to do is:
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;
/
Or better, just changing the cursor code:
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;
/
Upvotes: 2
Reputation: 1885
It seems that the CLI_ID
is mentioned as unique key
which means the dulicate will not accepted at any cost. wherears in the procedure line 9
has looped insert
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;
removing the unique contraint U_DIRECT_DEBIT_CLI_ID
will resolve your issue
Upvotes: 1