tags:

views:

115

answers:

4

I want to write a loop that iterates over numbers 105 102 19 17 101 16 106 107

for each iteration I want to plug the number in a query and insert it into a table.

pseudo:

LOOP (105 102 19 17 101 16 106 107)
   FETCH select * from some_table where value=current_iteration_index --105..etc.
   INTO my_rec_type

END LOOP;
+1  A: 

Here's an option, using a Cursor FOR LOOP, and the %ROWTYPE attribute:

DECLARE

  my_rec_type SOME_TABLE%ROWTYPE;

  CURSOR c IS 
    SELECT 105 AS c_index FROM DUAL
    UNION ALL
    SELECT 102 AS c_index FROM DUAL 
    UNION ALL
    SELECT 19 AS c_index FROM DUAL 
    UNION ALL
    SELECT 17 AS c_index FROM DUAL 
    UNION ALL
    SELECT 101 AS c_index FROM DUAL
    UNION ALL
    SELECT 16 AS c_index FROM DUAL 
    UNION ALL
    SELECT 106 AS c_index FROM DUAL
    UNION ALL
    SELECT 107 AS c_index FROM DUAL

BEGIN

  FOR cursor_rec IN c
  LOOP

     SELECT * 
       INTO my_rec_type
       FROM some_table 
       WHERE value = cursor_rec.c_index;

  END LOOP;

END;
OMG Ponies
my main concert is to break it into different queries. i dont want to do everything in one query by using union all
learn_plsql
@learn_plsql: See DCookie's answer then; it wasn't clear to me how you would get/supply the numbers specified into the query. Nothing wrong with using UNION ALL...
OMG Ponies
+2  A: 

Here's a more concise, albeit no less ugly, alternative:

DECLARE 
CURSOR C IS
SELECT val 
  FROM (SELECT LEVEL val FROM dual CONNECT BY LEVEL < 1000)
 WHERE val IN (105,102,19,17,101,16,106,107);
BEGIN
  FOR R IN C LOOP
    select * 
     INTO my_rec_type
     from some_table
    where value=R.val; --105..etc.
    ... more stuff
  END LOOP;
END;

The advantage here (IMO) is you only need to modify the IN list and perhaps the limit on the CONNECT BY clause to change your results.

DCookie
+1: Wish I'd thought of that
OMG Ponies
Is it possible to put results of the final `my_rec_type` into a cursor? OR insert results into a cursor in the loop?
learn_plsql
Not exactly sure what you are wanting to do. You can assign various fields in the my_rec_type record and then use the record to update the originally fetched record: my_rec_type.fieldname := 'some new value'; UPDATE some_table SET ROW = my_rec_type WHERE value = R.val;
DCookie
+4  A: 

Another method:

declare
 type numListType is table of number;
 numList numListType;
begin
numList := numListType(
 105,102,19,17,101,16,106,107 
);
for i in numList.FIRST..numList.LAST loop
 -- your usage of element goes here
 dbms_output.put_line(numList(i));
end loop;
end;
/
dpbradley
+3  A: 

While there are a couple of solutions to your questions, but based on your handle I'm going to tell you that I think you're approaching this the wrong way - you're not taking advantage of the features of the database.

Can you explain why

select * from some_table where value in (105, 102, 19, 17, 101, 16, 106, 107)

doesn't do what you want it to do?

chris
I thought the original posted pseudo code was just a simplification of something more procedurally complex, but of course if this is all that is needed then this is most efficient - +1 for considering the username.
dpbradley
Because the in-list doesn't contain commas? ;-)
Rob van Wijk
What do you mean? Of course it has commas :)
chris
@dpbradley: I've worked with enough inexperienced developers who try to apply procedural thinking at the database level to recognize it when I see it. Of course, I could be wrong, but the user name was a good clue.
chris
What is the source of the numbers? Is it a static list; another table; user/application input?
chilltemp
the back story is that i am running a huge query which brings 8 rows of data (each has id). This query takes 16 seconds to run. Our policy is strict that any query running over 8 seconds gets killed. So I thought I'll run same query 8 times. one time for each id. that is why I don't want to combine stuff
learn_plsql
Interesting policy. It would change a lot where I work. I'm assuming that you've already tested that selecting 1 value at a time works within the 8 second limitation.
chilltemp
So, they're paying developer's labor time to divide up queries to run in under 8 seconds. Wow...
DCookie
@learn_plsql - Changing the policy is probably out of your control, but this one is pretty silly. Tell your DBA's that you're actually doing more total work at the database level to work around this limitation. Oracle has resource profiling that could limit others to a lower value but make an exception for this task
dpbradley
I know guys this sucks. I am fed up but have to put up with this crappy policy. Basically policy was put in when we were in sql server. Because sql server locks tables...it was decided that if query is running for long then kill it so others can use that table. Then we moved to oracle and policy stayed...eventhough oracle does not lock tables. am i correct?
learn_plsql
@chilltemp yeah, I've tested that. each query takes about 2-3 seconds
learn_plsql
@learn_plsql: Fetch a copy of "Expert Oracle Database Architecture" by Tom Kyte, read it and you will have all the ammo you need to shoot down the crappy policy. Pay attention to the chapter on locking. Oracle is not SQL Server and vice-versa. If management still won't listen, then look for a job where you're not surrounded by idiots.
DCookie
Oracle does not lock tables except against DDL, unless you specifically ask for it. Record level locking is the norm, and Oracle has a very clever strategy for locking that is extremely efficient and non-resource intensive.
DCookie
@learn_plsql: one more point: with Oracle, readers never block writers, and writers never block readers. For the most part, the ONLY time (absent an explicit table level lock) you block is when two sessions try to update the same record. Even if you lock the table, other sessions can still query it.
DCookie