简体   繁体   中英

PL/SQL - Loop insert and select

I want a reusable script that can be configured by swapping out variable values. I am hoping to be able to loop over a collection of tag_ids and insert a row for each tag. Also I want to have a check either side of the insert for visual verification before committing.

This is what I have tried so far:

set verify off;
set serveroutput on;

define uname = 'foobar'
define f_name = 'foo'
define l_name = 'bar'

declare
 type numListType is table of number;
 numList numListType;

begin
numList := numListType(432,433,434,435);

for i in numList.FIRST..numList.LAST loop
    dbms_output.put_line('EXPECTING 0');
    select count(*)
    from security_tag_tbl
    where tag_id = numList(i);

    dbms_output.put_line('INSERTING ROW');
    insert into security_tag_tbl (id, username, first_name, last_name, tag_id)
    values (security_tag_tbl_seq.nextval, '&uname', '&f_name', '&l_name', numList(i));

    dbms_output.put_line('EXPECTING 1');
    select count(*)
    from security_tag_tbl
    where tag_id = numList(i);
end loop;
end;
/

set serveroutput off;
set verify on;

Issues with this sample:

  • This sample returns errors around the select query.
  • When I remove the select statements the sample code returns errors with indexes in 'numList'.

Any suggestions about the correct way to approach this scenario?

Ok, first of all, the above code contains a few problems. You can't use selects in PL/SQL without storing them in a variable with the INTO keyword.

To reproduce your problem, I used these script to create the table and sequence:

create table security_tag_tbl (id number, username varchar2(200), first_name varchar2(200), last_name varchar2(200), tag_id number);

create sequence security_tag_tbl_seq;

I then modified your code into this:

set verify off;
set serveroutput on;

define uname = 'foobar'
define f_name = 'foo'
define l_name = 'bar'

declare
 type numListType is table of number;
 numList numListType;

 firstcount number;
 secondcount number;

begin
numList := numListType(432,433,434,435);

for i in numList.FIRST..numList.LAST loop
    dbms_output.put_line('EXPECTING 0');
    select count(*)
    into firstcount
    from security_tag_tbl
    where tag_id = numList(i);

    dbms_output.put_line('GOT ' || firstcount);


    dbms_output.put_line('INSERTING ROW');
    insert into security_tag_tbl (id, username, first_name, last_name, tag_id)
    values (security_tag_tbl_seq.nextval, '&uname', '&f_name', '&l_name', numList(i));

    dbms_output.put_line('EXPECTING 1');
    select count(*)
    into secondcount
    from security_tag_tbl
    where tag_id = numList(i);

    dbms_output.put_line('GOT ' || secondcount);

end loop;
end;
/

set serveroutput off;
set verify on;

You will now get visual feedback about what's happening. Next question is, what to do when you don't get the desired result? You could go for a construction like this where you commit or rollback the transaction based on the results of those counts:

set verify off;
set serveroutput on;

define uname = 'foobar'
define f_name = 'foo'
define l_name = 'bar'

declare
 type numListType is table of number;
 numList numListType;

 firstcount number;
 secondcount number;
 errorocured boolean := false;

begin
numList := numListType(432,433,434,435);

for i in numList.FIRST..numList.LAST loop
    dbms_output.put_line('EXPECTING 0');
    select count(*)
    into firstcount
    from security_tag_tbl
    where tag_id = numList(i);

    dbms_output.put_line('GOT ' || firstcount);
    if (firstcount != 0) then
      errorocured := true;
    end if;


    dbms_output.put_line('INSERTING ROW');
    insert into security_tag_tbl (id, username, first_name, last_name, tag_id)
    values (security_tag_tbl_seq.nextval, '&uname', '&f_name', '&l_name', numList(i));

    dbms_output.put_line('EXPECTING 1');
    select count(*)
    into secondcount
    from security_tag_tbl
    where tag_id = numList(i);

    dbms_output.put_line('GOT ' || secondcount);

    if (secondcount != 1) then
      errorocured := true;
    end if;


end loop;


if errorocured = true  then
  dbms_output.put_line('Something wend wrong, rolling back batch');
  rollback;
else
  dbms_output.put_line('Everything ok, committing batch');
  commit;
end if;

end;
/

set serveroutput off;
set verify on;

You might also want to look into bulk operations if you're going to use this code for larger numbers or records. Good documentation about it can be found here: http://www.oracle-base.com/articles/9i/bulk-binds-and-record-processing-9i.php

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM