About PL/SQL printing syntax? [closed] - oracle

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 12 months ago.
Improve this question
Im trying to write a program in PL/SQL for printing prime numbers between 1 to 50 for that i use the following code-
DECLARE
i number(3);
j number(3);
BEGIN
i := 2;
LOOP
j := 2;
LOOP
EXIT WHEN((MOD(I,J) =0) OR (j=i));
j := j+1
END LOOP
IF LOOP;
IF(j=i) THEN
dbms_output,put(i); **//This line do nothing**
END IF;
i := i+1
exit WHEN i=50;
END LOOP;
END;
but is doesn't desplay anything.
I'm using Oracledb Standalone compiler/editor to run it.can anyone tell me what was the problem with that.

I haven't heard of this "Oracledb Standalone compiler/editor" that you are using, so consult the product documentation for how to enable DBMS Output, as it's not always enabled by default. You may need to find a menu bar checkbox or include a set server output on command before the start of the PL/SQL block.
Regarding the code, there are several issues that prevent it from compiling. Each statement must be terminated with a semicolon. Also to print a complete line with linefeed, you need to call dbms_output.put_line, because dbms_output.put only adds characters (to allow you to build a line incrementally, for example) and must be followed by put_line or new_line in order to output anything. I'm not sure what IF LOOP; is meant to do.
To separate your output display issue from the program logic for generating prime numbers, I recommend simplifying the code down to the simplest test case that reproduces the issue, for example,
begin
dbms_output.put_line('Hello, world!');
end;
Can you run this? Does your editor display output?
Here is a fixed version of your code:
declare
i number(3) := 2;
j number(3);
begin
-- i := 2; - moved to declaration
while i < 50 loop
j := 2;
loop
exit when((mod(i, j) = 0) or (j = i));
j := j + 1; -- missing semicolon
end loop; -- missing semicolon
if j = i then
dbms_output.put_line(i); -- put_line prints a line. put requires a newline
end if;
i := i + 1; -- missing semicolon
-- exit when i = 50; -- moved to loop definition
end loop;
end;

Related

PL SQL output in hackerrank

set serveroutput on;
DECLARE
I NUMBER;
J NUMBER;
BEGIN
FOR I IN REVERSE 1..20
LOOP
FOR J IN 1..I
LOOP
DBMS_OUTPUT.PUT('* ') ; -- printing *
END LOOP;
DBMS_OUTPUT.NEW_LINE; -- for new line
END LOOP;
END;
'
Can anyone tell me why this code is not showing any output in the Hackerank question (Draw The Triangle) even after selecting Oracle?
https://www.hackerrank.com/challenges/draw-the-triangle-1/problem
That site doesn't seem to ever show your the output from your submission, unhelpfully, but does with just 'run code'. Surprisingly it does seem to understand PL/SQL; and even more surprisingly it handles the set serveroutput on, which is a SQL\Plus/SQL Developer client command.
But you need to add a terminating / after your code, on a line on its own - again, just like SQL*Plus (though SQL Developer is sometimes doesn't complain):
END LOOP;
END;
/
Your code doesn't produce the expected output because it has a trailing space on each line. Instead of:
DBMS_OUTPUT.PUT('* ') ; -- printing *
skip the space on the last iteration:
DBMS_OUTPUT.PUT('*') ; -- printing *
IF J < I THEN
DBMS_OUTPUT.PUT(' ');
END IF;
So this produces the expected output, and passes the test:
set serveroutput on;
DECLARE
I NUMBER; -- redundant
J NUMBER; -- redundant
BEGIN
FOR I IN REVERSE 1..20
LOOP
FOR J IN 1..I
LOOP
DBMS_OUTPUT.PUT('*') ; -- printing *
IF J < I THEN
DBMS_OUTPUT.PUT(' ');
END IF;
END LOOP;
DBMS_OUTPUT.NEW_LINE; -- for new line
END LOOP;
END;
/
However, your original code also passes the test, despite the trailing spaces, if you just add the terminating /:

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;

PL/SQL - how to repeat alternating text for a given number of times with a final output?

I want to make a procedure called OE that will have text output based on the number that I define.
For example, inputting the number 6 will give the following output:
odd
even
odd
even
odd
even
= even steven!
and inputting the number 5 will give the following output:
odd
even
odd
even
odd
= you oddball!
I'm completely new at this and have been struggling to get the odd number to load correctly (for some reason, it gets stuck in an infinite loop). Any help would be appreciated! Here is what I got so far:
CREATE OR REPLACE procedure oe
(p_n IN number)
AS
v_n number;
v_on number;
BEGIN
v_n := p_n;
v_on := p_n;
IF v_n>0 THEN LOOP
dbms_output.put_line('odd');
v_n := v_n-1;
dbms_output.put_line('even');
v_n := v_n-1;
If v_n=0 then
exit;
if v_on mod 2 > 0 then dbms_output.put_line('=' || ' you oddball!');
exit;
else
dbms_output.put_line('=' || ' even steven!');
exit;
end if;
end if;
end loop;
end if;
END;
/
You are not using exit conditions properly hence your code is going in infinite loop. You simplify your logic as below. Let me know it it works for you.
You may add few validations to make sure you get proper input parameters such as p_n > 0 and other.
CREATE OR REPLACE procedure oe
(p_n IN number)
AS
begin
for i in 1..p_n
loop
if mod(i,2)=1 then dbms_output.put_line('odd');
else dbms_output.put_line('even');
end if;
end loop;
if mod(p_n,2)=1 then dbms_output.put_line('= you oddball!');
else dbms_output.put_line('= even steven!');
end if;
end;
hemalp108 has already answered this, but I just wanted to add that you don't even need the if/else logic that fills the procedure (except perhaps for handling values less than 1, which I'll leave as an exercise), because we have case:
create or replace procedure oe
( p_n in number )
as
begin
for i in 1 .. p_n loop
dbms_output.put_line(case mod(i,2) when 1 then 'odd' else 'even' end);
end loop;
dbms_output.put_line(case mod(p_n,2) when 1 then '= you oddball!' else '= even steven!' end);
end;
(You may also notice how laying your code out neatly is half the way towards debugging it.)

How to populate varray multiple times

I have a script that uses one VARRAY multiple times. But, I can't seem to figure out how to reset the VARRAY after looping through it once. I wrote the following basic script to help me troubleshoot:
DECLARE
TYPE multi_show_id_type IS VARRAY (60) OF VARCHAR2 (10);
multi_show_id multi_show_id_type := multi_show_id_type ();
counter NUMBER := 1;
i NUMBER := 1;
BEGIN
DBMS_OUTPUT.put_line ('BEGIN');
WHILE i < 10
LOOP
DBMS_OUTPUT.put_line (i);
--counter:=0;
--multi_show_id :=multi_show_id_type();
--multi_show_id.delete;
WHILE counter < 25
LOOP
multi_show_id.EXTEND ();
multi_show_id (counter) := counter * counter;
DBMS_OUTPUT.put_line ('VArray: [' || counter || '] [' || multi_show_id (counter) || ']');
counter := counter + 1;
END LOOP;
i := i + 1;
END LOOP;
DBMS_OUTPUT.put_line ('END');
END;
/
This script works when it is only looping through the array once. But if you uncomment the counter:=0 line, which forces it to loop through the array population loop 10 times, I get an ORA-06532 error. You can see some of the stuff I've tried in the other commented lines. Any help would be appreciated.
Actually, #akf is correct; your code as written won't work because a VARRAY starts at item 1, not zero.
Change your code thusly and it works:
...
LOOP
DBMS_OUTPUT.put_line (i);
counter:=1;
--multi_show_id :=multi_show_id_type();
multi_show_id.delete;
WHILE counter < 26
LOOP
...
EDIT: if you want to run thru the loop 25 times you do need to change the WHILE loop upper bound to 26...
there seems to be two problems here. first, the VARRAY index starts at 1. second, you will stop once your VARRAY is full at 60 items, as defined in your declaration.
use the following:
TYPE multi_show_id_type IS VARRAY (250) OF VARCHAR2 (10);
and
counter:=1;
uncomment the multi_show_id :=multi_show_id_type(); line if you want to start at 1 for each loop. if you want to ensure that no more than 4 values, your inner while loop should make that restriction.

'CONTINUE' keyword in Oracle 10g PL/SQL

I'm migrating a TSQL stored procedure to PL/SQL and have encountered a problem - the lack of a CONTINUE keyword in Oracle 10g.
I've read that Oracle 11g has this as a new feature, but upgrading is not an option unfortunately.
Is there any alternative to CONTINUE in 10g? I don't believe it's practical to restructure the logic of the SP as a work-around, because I have an outer loop, an IF, then a nested IF, then the CONTINUE at the end of a statement block within that IF.
Any help would be greatly appreciated, cheers.
You can simulate a continue using goto and labels.
DECLARE
done BOOLEAN;
BEGIN
FOR i IN 1..50 LOOP
IF done THEN
GOTO end_loop;
END IF;
<<end_loop>> -- not allowed unless an executable statement follows
NULL; -- add NULL statement to avoid error
END LOOP; -- raises an error without the previous NULL
END;
Though it's a bit complex and just a fake, you can use exception this way :
DECLARE
i NUMBER :=0;
my_ex exception;
BEGIN
FOR i IN 1..10
LOOP
BEGIN
IF i = 5 THEN
raise my_ex;
END IF;
DBMS_OUTPUT.PUT_LINE (i);
EXCEPTION WHEN my_ex THEN
NULL;
END;
END LOOP;
END;
In fact, PL SQL does have something to replace CONTINUE. All you have to do is to add a label (a name) to the loop :
declare
i integer;
begin
i := 0;
<<My_Small_Loop>>loop
i := i + 1;
if i <= 3 then goto My_Small_Loop; end if; -- => means continue
exit;
end loop;
end;
For future searches, in oracle 11g they added a continue statement, which can be used like this :
SQL> BEGIN
2 FOR i IN 1 .. 5 LOOP
3 IF i IN (2,4) THEN
4 CONTINUE;
5 END IF;
6 DBMS_OUTPUT.PUT_LINE('Reached on line ' || TO_CHAR(i));
7 END LOOP;
8 END;
9 /
Reached on line 1
Reached on line 3
Reached on line 5
PL/SQL procedure successfully completed.
It's not available in 10g, however it's a new feature in 11G
Can you refactor the IFs into a function, returning at the appropriate point (early if necessary). Then the control flow will pick up in the loop at the right place.
Does that make sense?
Not exactly elegant, but simple:
DECLARE
done BOOLEAN;
BEGIN
FOR i IN 1..50 LOOP
IF done THEN
NULL;
ELSE
<do loop stuff>;
END IF;
END LOOP;
END;
In Oracle there is a similar statement called EXIT that either exits a loop or a function/procedure (if there is no loop to exit from). You can add a WHEN to check for some condition.
You could rewrite the above example as follows:
DECLARE
done BOOLEAN;
BEGIN
FOR i IN 1..50 LOOP
EXIT WHEN done;
END LOOP;
END;
This may not be enough if you want to exit from deep down some nested loops and logic, but is a lot clearer than a couple of GOTOs and NULLs.
This isn't exactly an answer to the question, but nevertheless worth noting:
The continue statement in PL/SQL and all other programming languages which use it the same way, can easily be misunderstood.
It would have been much wiser, clearer and more concise if the programming language developers had called the keyword skip instead.
For me, with a background of C, C++, Python, ... it has always been clear what `continue' means.
But without that historical background, you might end intepreting this code
for i in .. tab_xy.count loop
CONTINUE WHEN some_condition(tab_xy(i));
do_process(tab_xy(i));
end loop;
like this:
Loop through the records of the table tab_xy.
Continue if the record fulfills some_condition, otherwise ignore this record.
Do_process the record.
This interpretation is completely wrong, but if you imagine the PL/SQL code as a kind of cooking receipt and read it aloud, this can happen.
In fact it happened to a very experienced development co-worker just yesterday.

Resources