Iterate through cursor and storing the output of the cursor in another table - for-loop

I am trying to iterate through a cursor which stores the value of the table. I use a FOR Loop to iterate and IF one of the conditions is met, I store the output in another table. I am not sure of the approach I am following and also getting error(ORA-00933: SQL command not ended properly). Stats_Queries is my reference table where I iterate my cursor through. STATS_RESULT_CARD is my output table where I have to store the results. Please help.
DECLARE
CURSOR c1 IS
select Stats_Queries.OBJECTTYPE, Stats_Queries.CATEGORY, Stats_Queries.QUERY
from Stats_Queries;
r1 c1%ROWTYPE;
BEGIN
FOR r1 IN c1 LOOP
If (r1.OBJECTTYPE = 'CARD') THEN
INSERT INTO STATS_RESULTS_CARD (NODETYPENAME, NODEDEFNAME , CARDTYPENAME, PROVISIONSTATUSNAME, STATDATE, CARDCOUNT)
select nt.name, nd.name, ct.name, ps.name, sysdate, count(c.cardid)
from cardtype ct, card c, node n, nodetype nt, nodedef nd, provisionstatus ps
where ct.name in ('SRA AMP', 'XLA AMP', 'SAM', 'ESAM')
and ct.cardtypeid = c.card2cardtype
and c.card2node = n.nodeid
and n.node2nodetype = nt.nodetypeid
and n.node2nodedef = nd.nodedefid
and c.card2provisionstatus = ps.provisionstatusid
group by nt.name, nd.name, ct.name, ps.name
END If;
END LOOP;
END;

As an aside from the answer that Finbarr has provided (which is perfectly correct; add in the missing semi-colon and your procedure should work), why do you need to loop through the cursor at all? That's the slow way of doing it.
You could just do a single insert statement instead, such as:
insert into stats_results_card (nodetypename,
nodedefname,
cardtypename,
provisionstatusname,
statdate,
cardcount)
select x.nt_name,
x.nd_name,
x.ct_name,
x.ps_name,
x.statdate,
x.cnt_cardid
from (select nt.name nt_name,
nd.name nd_name,
ct.name ct_name,
ps.name ps_name,
sysdate statdate,
count (c.cardid) cnt_cardid
from cardtype ct,
card c,
node n,
nodetype nt,
nodedef nd,
provisionstatus ps
where ct.name in ('SRA AMP',
'XLA AMP',
'SAM',
'ESAM')
and ct.cardtypeid = c.card2cardtype
and c.card2node = n.nodeid
and n.node2nodetype = nt.nodetypeid
and n.node2nodedef = nd.nodedefid
and c.card2provisionstatus = ps.provisionstatusid
group by nt.name,
nd.name,
ct.name,
ps.name) x
cross join (select stats_queries.objecttype,
stats_queries.category,
stats_queries.query
from stats_queries
where objecttype = 'CARD');
N.B. This assumes that there really isn't any link between the original cursor and the select statement that was inside the loop; we do a cross join to replicate the rows the required number of times.
If there was an actual join between the two queries, you would put that in place of the cross join.

ORA-00933: SQL command not ended properly
Probably occurring because you missed a semicolon after
group by nt.name, nd.name, ct.name, ps.name

Related

ORA-00947 not enough values with function returning table of records

So I'm trying to build a function that returns the records of items that are included in some client subscription.
So I've been building up the following:
2 types:
CREATE OR REPLACE TYPE PGM_ROW AS OBJECT
(
pID NUMBER(10),
pName VARCHAR2(300)
);
CREATE OR REPLACE TYPE PGM_TAB AS TABLE OF PGM_ROW;
1 function:
CREATE OR REPLACE FUNCTION FLOGIN (USER_ID NUMBER) RETURN PGM_TAB
AS
SELECTED_PGM PGM_TAB;
BEGIN
FOR RESTRICTION
IN ( SELECT (SELECT LISTAGG (ID_CHANNEL, ',')
WITHIN GROUP (ORDER BY ID_CHANNEL)
FROM (SELECT DISTINCT CHA2.ID_CHANNEL
FROM CHANNELS_ACCESSES CHA2
JOIN CHANNELS CH2
ON CH2.ID = CHA2.ID_CHANNEL
WHERE CHA2.ID_ACCESS = CMPA.ID_ACCESS
AND CH2.ID_CHANNELS_GROUP = CG.ID))
AS channels,
(SELECT LISTAGG (ID_SUBGENRE, ',')
WITHIN GROUP (ORDER BY ID_SUBGENRE)
FROM (SELECT DISTINCT SGA2.ID_SUBGENRE
FROM SUBGENRES_ACCESSES SGA2
JOIN CHANNELS_ACCESSES CHA2
ON CHA2.ID_ACCESS = SGA2.ID_ACCESS
JOIN CHANNELS CH2
ON CH2.ID = CHA2.ID_CHANNEL
WHERE SGA2.ID_ACCESS = CMPA.ID_ACCESS
AND CH2.ID_CHANNELS_GROUP = CG.ID))
AS subgenres,
CG.NAME,
A.BEGIN_DATE,
A.END_DATE,
CMP.PREVIEW_ACCESS
FROM USERS U
JOIN COMPANIES_ACCESSES CMPA
ON U.ID_COMPANY = CMPA.ID_COMPANY
JOIN COMPANIES CMP ON CMP.ID = CMPA.ID_COMPANY
JOIN ACCESSES A ON A.ID = CMPA.ID_ACCESS
JOIN CHANNELS_ACCESSES CHA
ON CHA.ID_ACCESS = CMPA.ID_ACCESS
JOIN SUBGENRES_ACCESSES SGA
ON SGA.ID_ACCESS = CMPA.ID_ACCESS
JOIN CHANNELS CH ON CH.ID = CHA.ID_CHANNEL
JOIN CHANNELS_GROUPS CG ON CG.ID = CH.ID_CHANNELS_GROUP
WHERE U.ID = USER_ID
GROUP BY CG.NAME,
A.BEGIN_DATE,
A.END_DATE,
CMPA.ID_ACCESS,
CG.ID,
CMP.PREVIEW_ACCESS)
LOOP
SELECT PFT.ID_PROGRAM, PFT.LOCAL_TITLE
BULK COLLECT INTO SELECTED_PGM
FROM PROGRAMS_FT PFT
WHERE PFT.ID_CHANNEL IN
( SELECT TO_NUMBER (
REGEXP_SUBSTR (RESTRICTION.CHANNELS,
'[^,]+',
1,
ROWNUM))
FROM DUAL
CONNECT BY LEVEL <=
TO_NUMBER (
REGEXP_COUNT (RESTRICTION.CHANNELS,
'[^,]+')))
AND PFT.ID_SUBGENRE IN
( SELECT TO_NUMBER (
REGEXP_SUBSTR (RESTRICTION.SUBGENRES,
'[^,]+',
1,
ROWNUM))
FROM DUAL
CONNECT BY LEVEL <=
TO_NUMBER (
REGEXP_COUNT (RESTRICTION.SUBGENRES,
'[^,]+')))
AND (PFT.LAUNCH_DATE BETWEEN RESTRICTION.BEGIN_DATE
AND RESTRICTION.END_DATE);
END LOOP;
RETURN SELECTED_PGM;
END FLOGIN;
I expect the function tu return a table with 2 columns containing all the records from table PROGRAMS_FT that are included in the user access.
For some reason, I'm getting compilation warning ORA-000947.
My understanding of the error code is that it occurs when the values inserted does not match the type of the object receiving the values, and I can't see how this can be the case here.
You're selecting two scalar values and trying to put them into an object. That doesn't happen automatically, you need to convert them to an object:
...
LOOP
SELECT PGM_ROW(PFT.ID_PROGRAM, PFT.LOCAL_TITLE)
BULK COLLECT INTO SELECTED_PGM
FROM PROGRAMS_FT PFT
...
(It's an unhelpful quirk of PL/SQL that it says 'not enough values' rather than 'too many values', as you might expect when you try to put two things into one; I'm sure I came up with a fairly convincing explanation/excuse for that once but it escapes me at the moment...)
I'm not sure your loop makes sense though. Assuming your cursor query returns multiple rows, each time around the loop you're replacing the contents of the SELECTED_PGM collection - you might think you are appending to it, but that's not how it works. So you will end up returning a collection based only on the final iteration of the loop.
Aggregating and then splitting the data seems like a lot of work too. You could maybe use collections for those; but you can probably get rid of the cursor and loop and combine the cursor query with the inner query, which would be more efficient and would allow you to do a single bulk-collect for all the combined data.

Cursor loop update Table by many values

DECLARE
CURSOR contacts
IS
SELECT SUM (budget) AS budget
FROM et_bp_gl_account a, et_bp_fact f
WHERE f.gl_account_id = a.gl_account_id
AND total_flag = 0
GROUP BY month_id, org_unit_id;
BEGIN
FOR r IN contacts
LOOP
UPDATE et_bp_fact
SET budget = r.budget
WHERE gl_account_id IN (SELECT total_element
FROM et_bp_gl_account g, et_bp_fact f
WHERE f.gl_account_id = g.gl_account_id);
END LOOP;
END;
I want to update the table ET_BP_FACT by many values example(25,50,75)
returned from Cursor but when i execute the table updated by (25,25,25)
I think there an issue in the loop
That's because the UPDATE's WHERE clause doesn't "reference" cursor's values. Something like this:
DECLARE
CURSOR contacts
IS
SELECT month_id, org_unit_id, --> include additional columns here ...
SUM (budget) AS budget
FROM et_bp_gl_account a, et_bp_fact f
WHERE f.gl_account_id = a.gl_account_id
AND total_flag = 0
GROUP BY month_id, org_unit_id;
BEGIN
FOR r IN contacts
LOOP
UPDATE et_bp_fact
SET budget = r.budget
WHERE gl_account_id IN
(SELECT total_element
FROM et_bp_gl_account g, et_bp_fact f
WHERE f.gl_account_id = g.gl_account_id
--
AND f.org_unit_id = r.org_unit_id --> ... and reference them here ...
AND g.month_id = r.month_id);
--> ... or, possibly, here
END LOOP;
END;
I'd suggest you to always precede column names with table aliases, because - looking at your code, there's no way to guess which table(s) MONTH_ID and ORG_UNIT_ID belong to, so my code might (or might not) work, but I hope you got the general idea.

Replacing DBMS_OUPUT in a PL/SQL test LOOP to return a collection

So I have this assignment where I have to create a stored procedure to search for movies in an Oracle DataBase.
The search string follow the following logic :
It looks for the year of the movie in parenthesis
Ex. (1992)
It looks for a range of year in brackets
Ex. [1992,2000]
It looks for a word contained in the title, country, realisator, genre, actors or scenarists.
Any of the above can be combined multiple times.
Ex. : The Lord Of the Ring Ian McKellen Christopher Lee [1992,2000]
The logic used to solve this problem was to make a giant query to group all the required data then use a cursor to loop through the result set with a cursor to check if every word of the search string is valid.
I managed to make a procedure that works as expected, but the only way I found to return the results was to use DBMS_OUTPUT. Now the problem is that when I plug this is Hibernate the DBMS_OUTPUT is not sent over to the client. I've read some way to force the output by setting DBMS_OUTPUT.enable, but I feel that this is not the proper way to do it.
So here are my questions :
Is my logic flawed? Is there a simpler way to archive this with a single select or something?
Is there a way to dynamically push data inside a cursor and return it?
Am I really supposed to trick the DBMS_OUTPUT so it is sent over to hibernate?
Here's my code :
CREATE OR REPLACE PROCEDURE p_SearchFilm(searchString IN VARCHAR2) IS
IsValid BOOLEAN;
y1 INTEGER;
y2 INTEGER;
subStrArray apex_application_global.vc_arr2;
term VARCHAR(100);
CURSOR films IS
Select FilmId, Titre, real.Prenom||' '||real.nom as Realisateur, anneeSortie, ListPays, ListGenres,
ListScenaristes, ListActeurs, langueOrigine
from Film
natural left join
(select FilmId, listagg(p.Nom, ',') within group (Order By p.nom) ListPays from Film
natural join Film_vs_pays
natural join Pays p
Group by FilmId)
natural left join
(select FilmId, listagg(g.Nom, ',') within group (Order By g.nom) ListGenres from Film
natural join Film_vs_Genre
natural join Genre g
Group by FilmId)
natural left join
(select FilmId, listagg(p.Prenom||' '||p.Nom, ',') within group (Order By p.nom) ListScenaristes from Film
natural join Scenariste s
join Personne p on s.personneId = p.personneId
Group by FilmId)
natural left join
(select FilmId, listagg(p.Prenom||' '||p.Nom, ',') within group (Order By p.nom) ListActeurs from Film
natural join Personnage perso
join Personne p on perso.personneId = p.personneId
Group by FilmId)
left join Personne real on real.personneId = realisateurId;
BEGIN
<<FILM_LOOP>>
FOR film IN films LOOP
subStrArray := apex_util.string_to_table(searchString, ' ');
FOR i in 1..subStrArray.count LOOP
IsValid:= FALSE;
term:= subStrArray(i);
IF REGEXP_LIKE(term, '\(\d{4}\)') THEN
IF film.anneeSortie = TO_NUMBER(regexp_substr(term, '\d{4}')) THEN
IsValid:= TRUE;
END IF;
ELSIF REGEXP_LIKE(term, '\[\d{4},\d{4}\]') THEN
y1:= regexp_substr(term, '\d{4}', 1, 1);
y2:= regexp_substr(term, '\d{4}', 1, 2);
IF film.anneeSortie BETWEEN y1 AND y2 THEN
IsValid:= TRUE;
END IF;
ELSE
IF UPPER(film.Titre||film.Realisateur||film.ListActeurs||film.ListScenaristes||film.ListGenres||film.ListPays||film.langueOrigine)
LIKE '%'||UPPER(term)||'%' THEN
IsValid:= TRUE;
END IF;
END IF;
IF NOT IsValid THEN
CONTINUE FILM_LOOP;
END IF;
END LOOP;
DBMS_OUTPUT.put_line(film.FilmId||'|'||film.Titre);
END LOOP;
END;
A small disclaimer here :
I saw some similar questions that addressed this issue, but the ones that used cursors were returning a complete select, not hand picked rows.
The question about DBMS_OUTPUT and Hibernate stated that it should be avoided.
The questions using piped rows seamed to work only with functions (Changing the procedure for a function called by the procedure could be a valid work around, I'd like to know if something else is possible before tho).
The use of the DBMS_OUTPUT package is pretty much bounded to developer executions of anonymous blocks, and hence not suited for your intended communication with the Hibernate framework.
If you already have a stored procedure to apply your filter and determine your positive results, a solution could be populate a temporary table with those positives, and then return an open cursor which will only have the data from that temporary table, something like:
create global temporary table movie_results( movie varchar2(200) ) on commit preserve rows;
Of course your temp table can have more columns, but let me leave it like this, just to illustrate my solution.
CREATE OR REPLACE PROCEDURE p_SearchFilm(searchString IN VARCHAR2, movies out SYS_REFCURSOR) IS
IsValid BOOLEAN;
y1 INTEGER;
y2 INTEGER;
subStrArray apex_application_global.vc_arr2;
term VARCHAR(100);
CURSOR films IS
Select FilmId, Titre, real.Prenom||' '||real.nom as Realisateur, anneeSortie, ListPays, ListGenres,
ListScenaristes, ListActeurs, langueOrigine
from Film
natural left join
(select FilmId, listagg(p.Nom, ',') within group (Order By p.nom) ListPays from Film
natural join Film_vs_pays
natural join Pays p
Group by FilmId)
natural left join
(select FilmId, listagg(g.Nom, ',') within group (Order By g.nom) ListGenres from Film
natural join Film_vs_Genre
natural join Genre g
Group by FilmId)
natural left join
(select FilmId, listagg(p.Prenom||' '||p.Nom, ',') within group (Order By p.nom) ListScenaristes from Film
natural join Scenariste s
join Personne p on s.personneId = p.personneId
Group by FilmId)
natural left join
(select FilmId, listagg(p.Prenom||' '||p.Nom, ',') within group (Order By p.nom) ListActeurs from Film
natural join Personnage perso
join Personne p on perso.personneId = p.personneId
Group by FilmId)
left join Personne real on real.personneId = realisateurId;
BEGIN
<<FILM_LOOP>>
FOR film IN films LOOP
subStrArray := apex_util.string_to_table(searchString, ' ');
FOR i in 1..subStrArray.count LOOP
IsValid:= FALSE;
term:= subStrArray(i);
IF REGEXP_LIKE(term, '\(\d{4}\)') THEN
IF film.anneeSortie = TO_NUMBER(regexp_substr(term, '\d{4}')) THEN
IsValid:= TRUE;
END IF;
ELSIF REGEXP_LIKE(term, '\[\d{4},\d{4}\]') THEN
y1:= regexp_substr(term, '\d{4}', 1, 1);
y2:= regexp_substr(term, '\d{4}', 1, 2);
IF film.anneeSortie BETWEEN y1 AND y2 THEN
IsValid:= TRUE;
END IF;
ELSE
IF UPPER(film.Titre||film.Realisateur||film.ListActeurs||film.ListScenaristes||film.ListGenres||film.ListPays||film.langueOrigine)
LIKE '%'||UPPER(term)||'%' THEN
IsValid:= TRUE;
END IF;
END IF;
IF NOT IsValid THEN
CONTINUE FILM_LOOP;
END IF;
END LOOP;
--DBMS_OUTPUT.put_line(film.FilmId||'|'||film.Titre);
insert into movie_results( movie )
values film.FilmId||'|'||film.Titre;
commit;
END LOOP;
open movies for
select *
from movie_results;
END;
Now your parameter 'movies' has all the positive results derived from your procedure, and all you'll have to do is read the cursor in Hibernate.
Note that, once you close your connection, the temporary table looses all the data and will be ready to use again when another session begins (always remember to close your Cursors/Connections).
The first part of this can probably be accomplished with just a query. You can define your search terms like this: How to declare variable and use it in the same SQL script? (Oracle SQL)
I'll leave the basic query writing to you (e.g. joining appropriate data), but your script will in effect look something like this:
DEFINE var_year1 = 1992;
DEFINE var_year2 = 1994;
DEFINE var_country = null;
DEFINE var_title = 'Lord Of The Rings';
DEFINE var_realisator = null;
DEFINE var_genre = null;
DEFINE var_actors = 'Ian';
DEFINE var_scenarists = 'Lee';
SELECT film_id, title, year
FROM ...
WHERE year BETWEEN &var_year1 AND &var_year2
AND UPPER(title) LIKE UPPER('%&var_title%')
AND UPPER(country) LIKE UPPER('%&var_country%')
AND UPPER(realisator) LIKE UPPER('%&var_realisator%')
AND UPPER(genre) LIKE UPPER('%&var_genre%')
AND UPPER(actors) LIKE UPPER('%&var_actors%')
AND UPPER(scenarists) LIKE UPPER('%&var_scenarists%');
/
The reason I only select film_id, title, and year is because the title and year will be distinct values to the film_id. There are a couple of ways to skin this cat, but it all revolves around using a LIKE statement with variables that you have defined. If you do not want to explicitly define the values in the script, you can use the ACCEPT command. Or, you can interface it with something else that applies those values into the variables.
With this approach, it was kind of a shot in the dark on how you really have your data laid out. But keep in mind good relational database management practices, and you should be able to turn this into a useable query.
Additional Method:
You can also use a series of subqueries to find the same data above using the like statements, then INNER JOIN them together to figure out which ones are in common. Example:
WITH sub_title AS (SELECT film_id FROM Film WHERE UPPER(title) LIKE UPPER('%&var_title%')),
...
sub_actor AS (SELECT film_id FROM (...) WHERE UPPER(actor) LIKE UPPER('%&var_actor%'))
SELECT film_id
FROM sub_title t
INNER JOIN sub_actor a ON a.film_id = t.film_id;
/
If you had searched for 'star war' in that, you would have returned for example
1 Star Wars A New Hope
2 Star Wars The Empire Strikes Back
3 Star Wars Return of the Jedi
Then in the second subquery if you had searched 'Donald Glover' you would have gotten
2 Star Wars The Empire Strikes Back
3 Star Wars Return of the Jedi
Then, the INNER JOIN would have given you ID numbers 2 and 3 because those were the only ones where all of the criteria were met. Repeat the process for your other search terms. I hope this helps.

PLSQL Loop taking lot of time to execute

I have a Oracle procedure which is updating below 10,000 records. if I run the normal SQL statement, it is returning the result immediately with in seconds(30).
same statment in procedure loop it is going to endlessly.
My loop statment below.
Note: data FIELD Data type is a clob not varchar2.
statment:
select
'LB_COPY_CHANGE-'||8 LAST_MODIFIED_BY,
rec.COR_ID_old,
rec.COR_ID_NEW,
replace(replace(replace(a.data,'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||','),''id':'||rec.COR_ID_OLD||',',''id':'||rec.COR_ID_NEW||','),'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||',') as data
from KPI_MET_FIELD_DATA a, CUSTOM_TEMP_TABLE_SESSION_1 rec
where A.cmf_fk_id in (145,146,147)
and TYPE_LB in (14,15,16)
and a.KDB_FK_ID in (
select distinct km.KDB_FK_ID
from KPI_MET_FIELD_DATA km , KPI_DET_BASE kp, KPI_REL_KPI_SCORECARD ksc, STR_DET_EMP_SCORECARD sc
where ksc.SDE_FK_ID=sc.SDE_PK_ID
and km.KDB_FK_ID = ksc.KDB_KPI_FK_ID
and km.is_deleted=0
and kp.kdb_pk_id = km.KDB_FK_ID
and kp.is_deleted=0
and km.cmf_fk_id in (145,146,147)
and sc.sdp_fk_id = 8)
and a.is_deleted=0
and (a.data like '%'||rec.COR_ID_OLD||'%');
FOR rec in (SELECT * FROM CUSTOM_TEMP_TABLE_SESSION where TYPE_LB in (14,15,16)) LOOP
update KPI_MET_FIELD_DATA
set LAST_MODIFIED_BY='LB_COPY_CHANGE-'||p2 ,
data = replace(replace(replace(data,'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||','),''id':'||rec.COR_ID_OLD||',',''id':'||rec.COR_ID_NEW||','),'''id'':'||rec.COR_ID_OLD||',','''id'':'||rec.COR_ID_NEW||',')
where cmf_fk_id in (145,146,147)
and KDB_FK_ID in (
select distinct km.KDB_FK_ID
from KPI_MET_FIELD_DATA km , KPI_DET_BASE kp, KPI_REL_KPI_SCORECARD ksc, STR_DET_EMP_SCORECARD sc
where ksc.SDE_FK_ID=sc.SDE_PK_ID
and km.KDB_FK_ID = ksc.KDB_KPI_FK_ID
and km.is_deleted=0
and kp.kdb_pk_id = km.KDB_FK_ID
and kp.is_deleted=0
and km.cmf_fk_id in (145,146,147)
and sc.sdp_fk_id = p2)
and is_deleted=0 ;
There are several weaknesses in your code.
WHERE KDB_FK_ID in (select distinct ... does not make any sense. There is no need to make DISTINCT for an IN () clause.
Use ANSI join syntax instead of old Oracle join syntax, it is less error-prone
But the main difference is, your loop does not contain join condition (a.data like '%'||rec.COR_ID_OLD||'%'), i.e. you update entire table KPI_MET_FIELD_DATA again and again for each row in CUSTOM_TEMP_TABLE_SESSION where TYPE_LB in (14,15,16)

Replace SELECT INTO statement with a cursor ORACLE

This is the query. How to replace SELECT INTO statement with a cursor?
I'm newbie in Oracle
Thanks for your help
SELECT CEQ_LISTE_TYPE_QUESTIONS.ID_LISTE_TYPE_QUESTION
INTO vintIdListeTypeQuestion
FROM CEQ_FORMULAIRES
inner join CEQ_LISTE_TYPE_QUESTIONS
on CEQ_LISTE_TYPE_QUESTIONS.ID_LISTE_TYPE_FORMULAIRE=CEQ_FORMULAIRES.ID_TYPE_FORMULAIRE
AND CEQ_LISTE_TYPE_QUESTIONS.WEBCODE='ITEM_BETA_LACTAMASE'
WHERE CEQ_FORMULAIRES.ID_FORMULAIRE=to_number(out_rec.ID_FORMULAIRE)
and ceq_formulaires.date_inactive is null;
The error tells you that the query returns more than 1 row, so you should determine which row you need. Here an example how to fetch the most recent row based on a date field I thought up in ceq_list_type_questions "some_date".
select max(q.id_liste_type_question) keep (dense_rank last order by q.some_date) into vintidlistetypequestion
from ceq_formulaires f
join ceq_liste_type_questions q on q.id_liste_type_formulaire = f.id_type_formulaire
where f.id_formulaire = to_number(out_rec.id_formulaire)
and f.date_inactive is null
and q.webcode = 'ITEM_BETA_LACTAMASE'
Well, if you want to process your multiple rows in a loop, it's as simple as
BEGIN
FOR curs IN (SELECT ceq_liste_type_questions.id_liste_type_question
FROM ceq_formulaires
INNER JOIN ceq_liste_type_questions ON ceq_liste_type_questions.id_liste_type_formulaire=ceq_formulaires.id_type_formulaire
AND ceq_liste_type_questions.webcode = 'ITEM_BETA_LACTAMASE'
WHERE ceq_formulaires.id_formulaire = TO_NUMBER(out_rec.id_formulaire)
AND ceq_formulaires.date_inactive IS NULL)
LOOP
DBMS_OUTPUT.PUT_LINE(curs.id_liste_type_question); -- do what you need to do
END LOOP;
END;
/
But, as BazzPsychoNut mentions, if it's a requirement that your SQL return/operate on a single row, you'll need to modify your query to meet that requirement.

Resources