Re: suggestions sought on returning rows from oracle proc and deleting them in same proc
- From: christian.merz@xxxxxxxxxxx (Christian Merz)
- Date: Thu, 23 Oct 2008 08:45:41 +0200
Hi Martin,
this is not Perl stuff but Oracle PL/SQL.
Just take your 'get' procedure:
>>>> PROCEDURE get(
>>>> pdt OUT mytable.created%TYPE,
>>>> pcur OUT SYS_REFCURSOR) AS
>>>> BEGIN
>>>> pdt := utc_timestamp();
>>>> OPEN pcur FOR
>>>> SELECT DISTINCT(id) FROM mytable WHERE created <= pdt;
>>>> END;
and try this -untested- code to delete the items immediately after working with them:
PROCEDURE doit AS
CURSOR curs IS
SELECT * FROM mytable
FOR UPDATE NOWAIT;
BEGIN
FOR rec IN curs
LOOP
EXIT WHEN rec%NOTFOUND;
-- do something useful with rec
-- ...
-- delete item
DELETE FROM mytable
WHERE CURRENT OF curs;
END LOOP;
-- COMMIT; -- if not done outside
-- EXCEPTION WHEN OTHERS THEN ROLLBACK;
-- probaly you would write a message in your error_log table ...?
END;
BTW: You should clerify your needs. The following is rather unspecific:
>>>> ... The perl code wants to select the current distinct values of
>>>> the "id" field, do something with them and then all rows which were
>>>> present when the select was issued need to be deleted (since then
>>>> more rows may have been added which must not be touched)...
SELECT DISTINCT(id) results in sets of IDs rather than single records. But you can only treat the latter ones in a LOOP.
cu, Christian
.From: Martin Evans [mailto:martin.evans@xxxxxxxxxxxx]have
Sent: 22 October 2008 17:19
To: Stewart Anderson
Cc: dbi-users
Subject: Re: suggestions sought on returning rows from oracle proc and
deleting them in same proc
Stewart Anderson wrote:Subject: suggestions sought on returning rows from oracle proc and
deleting them in same proc
Hi,
I am hoping someone might have had to do something like this andtheagood solution. I am using DBD::Oracle. I have a table with a simple
integer and a timestamp:
create mytable (id int, created timestamp);
The integer value may appear more than once and the timestamp isindeterminatetimestamp when the row was created (it is actually created via a
trigger). Other procedures write "id"s into the table at
usedtimes. The perl code wants to select the current distinct values ofthe"id" field, do something with them and then all rows which werepresentwhen the select was issued need to be deleted (since then more rowsmayhave been added which must not be touched).
This is easily achieved if I have two procs:
PROCEDURE get(
pdt OUT mytable.created%TYPE,
pcur OUT SYS_REFCURSOR) AS
BEGIN
pdt := utc_timestamp();
OPEN pcur FOR
SELECT DISTINCT(id) FROM mytable WHERE created <= pdt;
END;
and:
PROCEDURE delete(
pdt IN mytable.created%TYPE,
puid IN mytable.id%TYPE) AS
BEGIN
DELETE FROM mytable WHERE id = puid AND created <= pdt;
END;
Perl calls the first one to get the unique ids and the timestampthetoretrieve them, does something with the returned ids and then callshowever,second procedure one for each id to delete the rows. It doesprocs,rely on the timestamp_format as if it is changed to removemillisecondsfor instance the delete above may fail to find any rows (e.g.timestampused was 2008-10-01 14:20:10.5555 but timestamp format omits the
milliseconds then the timestamp pumped in to the second proc is
2008-10-01 14:20:10). As a result of this problem and it is 2
guaranteethis one ruled out.
Ideally I'd like to achieve this in one procedure so I canthenomatter what happens in the perl the returned rows are deleted fromnottable. At first I thought that as the number of distinct ids willintobethat many I could issue my select, loop through them putting themandan oracle table type, delete the rows in the real table then returntheoracle table type to perl. However, DBD::Oracle does not support
returning oracle table/array types other than via piped functions
e.g.,asI found, you cannot issue a delete statement in a piped functiontothe following does not work:
type mytype_t IS table of mytable.id%TYPE NOT NULL;
type mytype_a IS TABLE OF mytable.id%TYPE NOT NULL
INDEX BY BINARY_INTEGER;
FUNCTION f_xxx RETURN mytable_t PIPELINED AS
CURSOR cur(param_dt mytable.created%TYPE)
IS SELECT DISTINCT(id) FROM mytable WHERE
created <= param_dt;
i integer := 1;
dt mytable.created%TYPE;
vu mytable_a;
BEGIN
dt := utc_timestamp();
FOR row in cur(dt) LOOP
vu(i) := row.id;
i := i+1;
END LOOP;
-- following delete generates an error
DELETE FROM mytable where created <= dt;
FOR i in vu.first .. vu.last LOOP
PIPE row(vu(i));
END LOOP;
END;
The problem is returning multiple values from rows in a table backintoperl and simultaneously deleting same rows. It can be achieved if I
introduce a temporary table because the proc can select the rows
andthe temp table and delete the selected rows in the original tablewouldthe perl reads the temporary table but we try very hard to avoid
temporary tables.
If DBD::Oracle supported the return of oracle table types thisbeeasy.
- Follow-Ups:
- References:
- suggestions sought on returning rows from oracle proc and deleting them in same proc
- From: Martin Evans
- RE: suggestions sought on returning rows from oracle proc and deleting them in same proc
- From: Stewart Anderson
- Re: suggestions sought on returning rows from oracle proc and deleting them in same proc
- From: Martin Evans
- RE: suggestions sought on returning rows from oracle proc and deleting them in same proc
- From: Stewart Anderson
- suggestions sought on returning rows from oracle proc and deleting them in same proc
- Prev by Date: (Fwd) DBI.pm
- Next by Date: Re: suggestions sought on returning rows from oracle proc and deleting them in same proc
- Previous by thread: RE: suggestions sought on returning rows from oracle proc and deleting them in same proc
- Next by thread: Re: suggestions sought on returning rows from oracle proc and deleting them in same proc
- Index(es):
Relevant Pages
|