PL SQL output in hackerrank - oracle

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 /:

Related

ORA-06533: Subscript beyond count ORA-06512 in PL/SQL

i want to have 10 by 10 grid with numbers from 1 to 100
and it give me this error
ORA-06533: Subscript beyond count ORA-06512: at line 25
ORA-06512: at "SYS.DBMS_SQL", line 1721
i don't understand the error and i couldn't solve it
can someone please help me
DECLARE
-- PL SQL code to create and fill a two-dimensional array
-- create VARRAY type of 10 integers
TYPE array_10_int IS VARRAY(10) of PLS_INTEGER;
-- create VARRAY type of array_10_int
TYPE grid_100_int IS VARRAY(10) of array_10_int;
-- declare a variable of the grid_100_int type
grid_var grid_100_int;
-- declare counters
i PLS_INTEGER := 0;
j PLS_INTEGER :=0;
M PLS_INTEGER :=0;
N PLS_INTEGER :=0;
BEGIN
grid_var := grid_100_int();
-- TO DO : use nested loop to fill grid_var with numbers 1- 100
/** YOUR CODE HERE **/
M:=0;
Loop
M:=M+1;
N:=0;
LOOP
J:=j+1;
If grid_var(M)(N)<100 THEN
DBMS_OUTPUT.PUT(' ' || grid_var(M)(N) || ' ');
ELSE
DBMS_OUTPUT.PUT( grid_var(M)(N) || ' ');
END IF;
EXIT WHEN (N =100);
END LOOP;
dbms_output.put_line(' ');
EXIT WHEN (M=10);
END LOOP;
-- Print the grid with nested loop
i:=0;
LOOP --outer loop
i := i+1;
j := 0;
LOOP -- inner loop
j:= j+1;
IF grid_var(i)(j) < 10 THEN
DBMS_OUTPUT.PUT(' ' || grid_var(i)(j) || ' ');
ELSE
DBMS_OUTPUT.PUT( grid_var(i)(j) || ' ');
END IF;
EXIT WHEN (j =10);
END LOOP;
dbms_output.put_line(' ');
EXIT WHEN (i =10);
END LOOP;
END;
A second look.
Creating multiple dimensional arrays (10 x 10) are tricky things. They are actually a collection of a collection. Further, each has the same definition and existence requirements: the element must exist before referenced, either by extend or array initialization. The following initializes each array before referencing it. Also it uses a FOR loop letting Postgres handle the setting, incrementing subscripts and loop exiting, rather than manually. See demo.
declare
-- PL SQL code to create and fill a two-dimensional array
-- create VARRAY type of 10 integers
type array_10_int is varray(10) of pls_integer;
-- create VARRAY type of array_10_int
type grid_100_int is varray(10) of array_10_int ;
-- declare a variable of the grid_100_int type
grid_var grid_100_int;
begin
grid_var := grid_100_int(null,null,null,null,null,null,null,null,null,null); -- initialize outer array
-- TO DO : use nested loop to fill grid_var with numbers 1- 100
/* YOUR CODE HERE */
for m in 1 .. 10
loop
grid_var(m) := array_10_int(null,null,null,null,null,null,null,null,null,null); -- initialize the inner array
for n in 1 .. 10
loop
grid_var(m)(n) := 10*(m-1)+ n;
end loop ;
end loop;
-- Print the grid with nested loop
for m in 1 .. 10
loop
for n in 1 .. 10
loop
dbms_output.put_line ('grid_var(' || to_char(m)
|| ')(' || to_char(n)
|| ') = ' || to_char(grid_var(m)(n))
);
end loop ;
end loop;
end;
Take away: Creating and using multiple dimensional arrays in Oracle is doable. But use them only when there is no other option. They add considerable complexity, usually unnecessary, and are poorly understood. (The above one is vary simple.)
Take away 2 Let Postgres control your loops. Less error prone, less code, easier to read.
PL/SQL array index begin with 1. But in the following code the local variable n is 0 when first used as an index.
Loop
M:=M+1;
N:=0;
LOOP
J:=j+1;
If grid_var(M)(N)<100 THEN --<<< n is 0 which throws your exception.
...
EXIT WHEN (N =100); --<<< NEVER occurs, N is not
Unfortunately, this is not your only issue (in this logic). You exit statement is condition EXIT WHEN (N =100); will never be met. You initialize the variable n before entering the loop, but never increment it in the loop.
Adjust the above to:
Loop
M:=M+1;
N:=1; -- <<< change here
LOOP
J:=j+1;
If grid_var(M)(N)<=100 THEN
...
EXIT WHEN (N >100); --<<< NEVER occurs, N is not incremented in the loop;
END LOOP;
Your other loop does not appear to have the same issue, but you should check it.

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

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 find a dbms_output.put_line() alternative to print contents line by line every time when it gets called in every iteration?

I want to view the output as the program goes while processing some records. Reading the line will not help, as it just retrieves is from the buffer and nothing else. For example:
DECLARE
CURSOR cEmploee IS SELECT * FROM g_emploees;
iTotal INTEGER := 0;
iCount INTEGER := 0;
BEGIN
SELECT COUNT(*) FROM g_emploees INTO iTotal;
FOR rLine IN cEmploee loop
dbms_output.put_line('Porcessed['||rLine.id||']: '|| ((iCount/iTotal)*100) || '%')
iCount := iCount + 1;
END LOOP;
END;
I cannot use dbms_output.get_line(), So stop marking it answered !
I cannot pipe the output to a file for read-only reasons !
Is there a command/setting for DBMS that I can use in order to view the processed % and print the line for processed in EVERY ITERATION and not at the end as a whole bunch of lines persisting in the buffer (The line printed must show every and exact time in PL/SQL when "dbms_output.put_line" is called not like 500 lines at the end of the execution) ??
CREATE OR REPLACE FUNCTION test_pipe
RETURN sys.DBMS_DEBUG_VC2COLL
pipelined
as
CURSOR cEmploee IS
SELECT * FROM g_emploees;
iTotal INTEGER := 0;
iCount INTEGER := 0;
BEGIN
SELECT COUNT(*)
INTO iTotal
FROM g_emploees ;
FOR rLine IN cEmploee loop
PIPE row('Porcessed['||rLine.id||']: '|| ((iCount/iTotal)*100) || '%');
iCount := iCount + 1;
END LOOP;
END;
/
--execute below statements ON command window :
SQL >set arraysize 1
SQL > SELECT * FROM TABLE(test_pipe);

Resources