What is purpose of NULL at the end of this loop? - oracle

Revising an old program. It issues NULL; and the end of this loop.
Why? What is it supposed to do? Nothing as far as I can tell.
Here is the loop:
--Price Break Loop
OPEN c_price_breaks;
<<c_price_breaks_loop>>
l_prc_brk_count := 1;
LOOP
dbms_output.put_line('Price break loop..');
fnd_file.put_line(fnd_file.log,'Price break loop..');
--FOR prc_brk_cnt IN 1..L_prc_brk_count LOOP
FETCH c_price_breaks INTO l_price_override, l_ship_to_organization_id_pb, l_ship_to_organization_code_pb, l_ship_to_location_id_pb, l_ship_to_location_code_pb, l_quantity;
EXIT WHEN c_price_breaks%NOTFOUND;
--Inserting into line location interface table
INSERT INTO PO.PO_LINE_LOCATIONS_INTERFACE (
INTERFACE_LINE_LOCATION_ID,
INTERFACE_HEADER_ID,
INTERFACE_LINE_ID,
SHIPMENT_TYPE,
SHIPMENT_NUM,
SHIP_TO_ORGANIZATION_ID,
SHIP_TO_LOCATION_ID,
QUANTITY,
UNIT_OF_MEASURE,
PRICE_OVERRIDE,
CREATION_DATE
) VALUES (
po_line_locations_interface_s.nextval, --INTERFACE_LINE_LOCATION_ID,
po_headers_interface_s.currval, --INTERFACE_HEADER_ID,
po_lines_interface_s.currval, --INTERFACE_LINE_ID,
'QUOTATION', --SHIPMENT_TYPE,
l_prc_brk_count, --SHIPMENT_NUM,
l_ship_to_organization_id_pb, --SHIP_TO_ORGANIZATION_ID,
l_ship_to_location_id_pb, --SHIP_TO_LOCATION_ID,
l_quantity, --QUANTITY,
l_unit_of_measure, --UOM
l_price_override, --PRICE_OVERRIDE
SYSDATE --CREATION_DATE,
);
l_prc_brk_count := l_prc_brk_count+1;
<<END_of_c_price_breaks_loop>>
NULL;
END LOOP; --END of Price break loop

Yes, the NULL is required while you have a label at the end of the PL/SQL block formed by the LOOP.
The Oracle documentation for the GOTO statement states:
GOTO Statement
The GOTO statement branches unconditionally to a statement label or block label. The label must be unique within its scope and must precede an executable statement or a PL/SQL block. The GOTO statement transfers control to the labelled statement or block.
The <<END_of_c_price_breaks_loop>> is a label and it must precede an executable statement or a PL/SQL block; NULL; is such a statement.
DECLARE
l_prc_brk_count PLS_INTEGER;
BEGIN
<<c_price_breaks_loop>>
l_prc_brk_count := 1;
LOOP
dbms_output.put_line('Price break loop..');
EXIT WHEN l_prc_brk_count > 3;
l_prc_brk_count := l_prc_brk_count+1;
<<END_of_c_price_breaks_loop>>
NULL;
END LOOP; --END of Price break loop
END;
/
Outputs:
Price break loop..
Price break loop..
Price break loop..
Price break loop..
Removing the NULL;
DECLARE
l_prc_brk_count PLS_INTEGER;
BEGIN
<<c_price_breaks_loop>>
l_prc_brk_count := 1;
LOOP
dbms_output.put_line('Price break loop..');
EXIT WHEN l_prc_brk_count > 3;
l_prc_brk_count := l_prc_brk_count+1;
<<END_of_c_price_breaks_loop>>
END LOOP; --END of Price break loop
END;
/
Gives:
ORA-06550: line 13, column 3:
PLS-00103: Encountered the symbol "END" when expecting one of the following:
( begin case declare exit for goto if loop mod null raise
return select update while with <an identifier>
<a double-quoted delimited-identifier> <a bind variable> <<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
Removing the label:
DECLARE
l_prc_brk_count PLS_INTEGER;
BEGIN
<<c_price_breaks_loop>>
l_prc_brk_count := 1;
LOOP
dbms_output.put_line('Price break loop..');
EXIT WHEN l_prc_brk_count > 3;
l_prc_brk_count := l_prc_brk_count+1;
END LOOP; --END of Price break loop
END;
/
Gives:
Price break loop..
Price break loop..
Price break loop..
Price break loop..
db<>fiddle here

The null is there because there has to be a statement after a label. If you try to run this block, for example
declare
l_cnt integer := 0;
begin
loop
exit when l_cnt > 1;
l_cnt := l_cnt + 1;
<<foo>>
end loop;
end;
you'll get a syntax error because the label foo doesn't have an executable statement after it. If you add a null;, the block compiles
declare
l_cnt integer := 0;
begin
loop
exit when l_cnt > 1;
l_cnt := l_cnt + 1;
<<foo>>
null;
end loop;
end;
Now, it doesn't appear that either of the labels in the code you posted are actually doing anything useful themselves (other than maybe functioning as comments?). Unless you have code somewhere else that has a goto one of these labels, you could eliminate both the c_price_breaks_loop label and the END_of_c_price_breaks_loop label and then you can get rid of the null; statement.

Related

Oracle forms 10g, copy multiple rows to another block

I'm new to oracle forms and i have a problem. I have two multiple records blocks with same fields in the form.
I query data for one block, it gets populated .
After that i need to copy all rows to new block. One helpful guy suggested following, but it keeps me in endless loop. Can you please help me resolve this?
:
declare
-- local variables; should contain all items you'd want to copy
l_empno emp.empno%type;
l_ename emp.ename%type;
l_job emp.job%type;
-- l_currec will contain current row number in the first block
l_currec number := 0;
-- l_exit will be used if we're at the end of the first block
l_exit varchar2(1) := 'N';
begin
loop
-- go to the source (first block) and the [last row you were in + 1]
go_block('first');
l_currec := l_currec + 1;
go_record(l_currec);`
-- check whether this is the last row of the first block; if so, exit the loop
if :system.last_record = 'true' then
l_exit := 'Y';
end if;
-- save current row's items
l_empno := :first.empno;
l_ename := :first.ename;
l_job := :first.job
-- go to the second block's bottom and create a new record
go_block('second');
last_record;
create_record;
-- put stored values into the second block's items
:second.empno := l_empno;
:second.ename := l_ename;
:second.job := l_job;
-- exit the loop if this was the last record to be copied
exit when l_exit = 'Y';
end loop;
end;
end;
if :system.last_record = 'true' then
:system.last_record returns 'TRUE' or 'FALSE' (in uppercase), so this IF statement will never be true. The 'true' in quotes must be 'TRUE'.

Write a PL/SQL block to insert numbers into the MESSAGES table. Insert the numbers 1 through 10, excluding 6 and 8

I'm trying to figure out how to exclude these numbers(6 and 8) when the loop happens. Also, for this question, I CAN'T use FOR and WHILE loops. The question states to ONLY use a basic loop since the lessons after will teach me how to use it. Also, does anyone know if I'm allowed to insert multiple END LOOPs? It's also possible that this syntax may not be legal.
EDIT: I'm pretty sure I've tried doing IF v_results >10 THEN EXIT; but the same error message occurred.
DECLARE
v_results messages.results%TYPE := 0 ; --data type is NUMBER
BEGIN
LOOP
SELECT results INTO v_results
FROM messages;
v_results := v_results + 1; --to increment
IF v_results = ANY(6,8)
THEN
END LOOP; --i thought maybe if I added this, the loop can start over
ELSE
INSERT INTO MESSAGES(results)
VALUES (v_results);
EXIT WHEN v_results >10;
END IF;
END LOOP;
END;
The error that I am getting.
ORA-06550: line 15, column 9:
PLS-00103: Encountered the symbol "END" when expecting one of the following:
( begin case declare exit for goto if loop mod null pragma
raise return select update while with
<<
continue close current delete fetch lock insert open rollback
savepoint set sql execute commit forall merge pipe purge
You could just avoid the 6 and 8 by adding 1 into it using the IF statement. There is no need for ELSE statement.
Also, you will need to use MAX function while fetching data from the MESSAGE table so that it can return the only max number. Without MAX function, you will get an error of -- multiple rows returned.
END LOOP must be associated with a single LOOP statement. so you can not write two END LOOP when there is a single LOOP statement.
DECLARE
V_RESULTS MESSAGES.RESULTS%TYPE := 0; --data type is NUMBER
BEGIN
LOOP
SELECT
MAX(RESULTS) -- used max to find ONLY ONE MAX RECORD
INTO V_RESULTS
FROM
MESSAGES;
V_RESULTS := NVL(V_RESULTS, 0) + 1; --to increment
IF V_RESULTS IN ( -- used in here
6,
8
) THEN
V_RESULTS := V_RESULTS + 1;
END IF;
INSERT INTO MESSAGES ( RESULTS ) VALUES ( V_RESULTS );
EXIT WHEN V_RESULTS >= 10;
END LOOP;
END;
db<>fiddle demo
Cheers!!
declare
i number:=1;
begin
loop
if i not in(6,8) then
insert into msg values(i);
end if;
i :=i+1;
exit when i>10;
end loop;
end;

How to get the output of an unnamed PL/SQL block in Oracle SQL Worksheet online? It's showing Unsupported Command for SET SERVEROUTPUT ON;

I'm trying PL/SQL on online Oracle SQL Worksheet - Live Oracle SQL.
I'm unable to display the output of the block, in spite of adding SET SERVEROUTPUT ON;
This is my code
SET SERVEROUTPUT ON;
declare
i number:=2;
j number:=0;
counter number:=0;
flag number;
begin
loop
if (i=2) then
counter:=counter+1;
dbms_output.put(i ||' ');
else
j:=2;
flag:=0;
loop
if(mod(i, j)=0) then
flag:=1;
end if;
exit when (i=j) or flag=1;
end loop;
if(flag=0) then
counter:=counter+1;
dbms_output.put(j ||' ');
end if;
end if;
i:=i+1;
exit when counter=10;
end loop;
end;
/
This is the console message
Unsupported Command
Statement processed.
Any idea how to get it working?
I actually changed dbms_output.put() to dbms_output.put_line() and it worked. Any idea how to make dbms_output.put() work?
I want the output in a single line.
DBMS_OUTPUT will only output to the console when a full line of output has been produced. If you only use DBMS_OUTPUT.PUT and don't call DBMS_OUTPUT.PUT_LINE or DBMS_OUTPUT.NEW_LINE then the output will sit in a buffer somewhere but will never be written to the console.
From the Oracle [DBMS_OUTPUT.PUT] documentation:
Usage Notes:
When you call PUT_LINE the item you specify is automatically followed by an end-of-line marker. If you make calls to PUT to build a line, then you must add your own end-of-line marker by calling NEW_LINE. GET_LINE and GET_LINES do not return lines that have not been terminated with a newline character.
You want to add DBMS_OUTPUT.NEW_LINE (or DBMS_OUTPUT.PUT_LINE( NULL )) at the end of your PL/SQL block.
A simplified version of your code (that only checks odd numbers) is:
DECLARE
i PLS_INTEGER :=1;
j PLS_INTEGER;
counter PLS_INTEGER :=1;
BEGIN
DBMS_OUTPUT.PUT('2 ');
LOOP
i:=i+2;
j:=3;
LOOP
EXIT WHEN mod(i, j)=0;
j:= j + 2;
END LOOP;
IF i = j THEN
-- prime found
DBMS_OUTPUT.PUT(i ||' ');
counter:=counter+1;
EXIT WHEN counter >= 10;
END IF;
END LOOP;
DBMS_OUTPUT.NEW_LINE;
END;
/
Which outputs:
2 3 5 7 11 13 17 19 23 29
Comment out that DBMS_OUTPUT.NEW_LINE; line and the procedure will not output anything as the buffer is never flushed to the console.
db<>fiddle here

loop counter case in oracle procedure

Is there any loop counter in procedure.
How to handle below case.
BEGIN
FOR recAnnLang IN getLang(var_non_subscribe)
LOOP
// if loop 1 recAnnLangCode.Ann_Lang assign to var1
var1 := recAnnLangCode.Ann_Lang;
// if loop 2 recAnnLangCode.Ann_Lang assign to var2
var2 := recAnnLangCode.Ann_Lang;
// if loop 3 recAnnLangCode.Ann_Lang assign to var2
var3 := recAnnLangCode.Ann_Lang;
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('Debug :: Inside Exception because data not found ' );
END;
DECLARE n_counter NUMBER := 0;
BEGIN
LOOP
n_counter := n_counter + 1;
DBMS_OUTPUT.PUT_LINE(n_counter);
IF n_counter = 5 THEN
EXIT;
END IF;
END LOOP;
END;
I did it like this.
maybe you are looking for something like
declare
type a_type is table of recAnnLang.Ann_Lang%type index by pls_integer;
val a_type;
begin
for recAnnLang in getLang(var_non_subscribe) loop
val(nvl(val.last, 0) + 1) := recAnnLang.Ann_Lang;
end loop;
for i in 1 .. val.last loop
dbms_output.put_line(val(i));
end loop;
end;
maybe,if getlang is an explicit cursor,you may think of using rownum in the cursor query select clause and use it as the counter.

PLS-00103: Encountered the symbol "1" when expecting one of the following: (

Wrote the following PLSQL script to produce a report and am getting the error messages
Error at line 5
ORA-06550: line 61, column 18:
PLS-00103: Encountered the symbol "1" when expecting one of the following:
(
I've been through the code many times and I cannot find the error. Any help would be greatly appreciated.
I'm currently working in Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
SET serveroutput ON size 1000000;
DECLARE
TYPE TITLE_RECORD_TYPE IS RECORD
(id number(19),
gaid varchar2(20),
artist_legal_name varchar2(510),
artist_display_title varchar2(510),
display_title varchar2(510),
category varchar2(255),
type varchar2(255),
sub_type varchar2(255));
TITLE_RECORD TITLE_RECORD_TYPE;
v_title varchar2(510);
v_artist varchar2(510);
v_total_rows_error number(20) := 0;
v_row_count number(10) := 0;
v_error_desc varchar2(200) := NULL;
v_error_code number(19);
CURSOR ARTIST_TITLE_CURSOR is
select track_artist,track_title
from asset_artist_title;
CURSOR QUERY_CURSOR is
select distinct g1.gaid,g2.legal_name,g1.artist_display_title,
g1.display_title,g1.category,g1.type,g1.sub_type
from gcdm_app_rpt.rpt_asset g1,
gcdm_app_rpt.rpt_artist g2
where g1.artist_id = g2.id
and g1.is_deleted <> 'Y'
and g1.is_core = 'Y'
and g2.is_core = 'Y'
and g1.title like v_title||'%'
and g1.artist_display_title like v_artist||'%';
BEGIN
OPEN ARTIST_TITLE_CURSOR;
LOOP
FETCH ARTIST_TITLE_CURSOR into v_artist,v_title;
EXIT WHEN ARTIST_TITLE_CURSOR%NOTFOUND or ARTIST_TITLE_CURSOR%NOTFOUND IS NULL;
SELECT count(*)
INTO v_row_count
FROM gcdm_app_rpt.rpt_asset g1,
gcdm_app_rpt.rpt_artist g2
WHERE g1.artist_id = g2.id
AND g1.is_core = 'Y'
AND g1.is_deleted <> 'Y'
AND g2.is_core = 'Y'
AND g1.title like v_title||'%'
AND g1.artist_display_title like v_artist||'%';
IF v_row_count < 1 THEN
v_error_desc := 'Matching Asset record for '||v_artist||' - '||v_title||' not found';
DBMS_OUTPUT.PUT_LINE('Error: '||v_error_desc||'.');
v_row_count := 0;
v_total_rows_error := v_total_rows_error + 1;
ELSE
OPEN QUERY_CURSOR
FOR i in 1..ARTIST_TITLE_CURSOR
LOOP
FETCH QUERY_CURSOR into TITLE_RECORD;
EXIT WHEN QUERY_CURSOR%NOTFOUND or QUERY_CURSOR%NOTFOUND IS NULL;
DBMS_OUTPUT.PUT_LINE(title_record.id,title_record.gaid,title_record.artist_legal_name,title_record.artist_display_name,
title_record.display_title,title_record.category,title_record.type,title_record.sub_type);
END LOOP;
CLOSE QUERY_CURSOR;
v_row_count := 0;
END IF;
END LOOP;
CLOSE ARTIST_TITLE_CURSOR;
DBMS_OUTPUT.PUT_LINE(chr(0));
IF v_total_rows_error > 0 THEN
DBMS_OUTPUT.PUT_LINE('Total Rows in error: '||v_total_rows_error);
END IF;
DBMS_OUTPUT.PUT_LINE(CHR(0));
EXCEPTION
WHEN OTHERS THEN
v_error_desc := SQLERRM;
v_error_code := SQLCODE;
DBMS_OUTPUT.PUT_LINE('Error: '||v_error_desc||' - '||v_error_code);
END;
It's line 67 in what you've posted, not 61, but still; this line is not right:
FOR i in 1..ARTIST_TITLE_CURSOR
You're trying to loop over a range of numbers - perhaps you wanted the number of records returned by the cursor, which you can't get - but your end 'number' is a cursor, so not legal in that context.
But it seems to be completely out of place anyway as you're looping over the QUERY_CURSOR records, so I wouldn't think the ARTIST_TITLE_CURSOR is relevant at this point. And you aren't attempting to use i. It looks like you can just remove that line.
More importantly, the previous line is missing a semi-colon:
OPEN QUERY_CURSOR;
Because it doesn't have one it's seeing the FOR and expecting a cursor query.
Following up on comments about why you have that FOR 1..v_row_count, it's still a bit redundant. You're limiting the number of fetches you do to match the count you got previously, from essentially the same query as you have in the cursor, which means you don't quite ever hit the EXIT WHEN QUERYCURSOR%NOTFOUND condition - that would come from the v_row_count+1 loop iteration. Normally you wouldn't know how many rows you expect to see before you loop over a cursor.
You don't really need to know here. The count query is repetitive - you're querying the same data you then have to hit again for the cursor, and you have to maintain the query logic in two places. It would be simpler to forget the count step, and instead keep a counter as you loop over the cursor; then handle the zero-rows condition after the loop. For example:
DECLARE
...
BEGIN
OPEN ARTIST_TITLE_CURSOR;
LOOP
FETCH ARTIST_TITLE_CURSOR into v_artist,v_title;
EXIT WHEN ARTIST_TITLE_CURSOR%NOTFOUND;
-- initialise counter for each ARTIST_TITLE
v_row_count := 0;
OPEN QUERY_CURSOR;
LOOP
FETCH QUERY_CURSOR into TITLE_RECORD;
EXIT WHEN QUERY_CURSOR%NOTFOUND;
-- increment 'found' counter
v_row_count := v_row_count + 1;
DBMS_OUTPUT.PUT_LINE(title_record.id
||','|| title_record.gaid
||','|| title_record.artist_legal_name
||','|| title_record
||','|| artist_display_name
||','|| title_record.display_title
||','|| title_record.category
||','|| title_record.type
||','|| title_record.sub_type);
END LOOP;
CLOSE QUERY_CURSOR;
-- now check if we found anything in the QUERY_CURSOR loop
IF v_row_count < 1 THEN
v_error_desc := 'Matching Asset record for '||v_artist||' - '||v_title||' not found';
DBMS_OUTPUT.PUT_LINE('Error: Matching Asset record for '
|| v_artist || ' - ' || v_title || ' not found.');
v_total_rows_error := v_total_rows_error + 1;
END IF;
END LOOP;
CLOSE ARTIST_TITLE_CURSOR;
--DBMS_OUTPUT.PUT_LINE(chr(0));
-- presumably this was meant to put out a blank line; use this instead
DBMS_OUTPUT.NEW_LINE;
IF v_total_rows_error > 0 THEN
DBMS_OUTPUT.PUT_LINE('Total Rows in error: '||v_total_rows_error);
END IF;
--DBMS_OUTPUT.PUT_LINE(CHR(0));
DBMS_OUTPUT.NEW_LINE;
END;
I've also taken out the exception handler because it isn't really adding anything; you'd see the code and message without it, even if you didn't have server output on; and catching WHEN OTHERS is a bad habit to get into.
You also don't need to declare your record type. You could use an implicit cursor anyway and avoid the type and variable completely, but even with the cursor definition you have, you could put this afterwards instead:
TITLE_RECORD QUERY_CURSOR%ROWTYPE;
There are various ways to open and loop over cursors, and you're using one of the more explicit ones - which isn't a bad thing for learning about them, but be aware of the options too.

Resources