Looping statement - sql

I am working on a loop to bring back the times tables from 1-12. I have completed this by using the following:
BEGIN
FOR i IN 1..12
LOOP
FOR j IN (i)..12
LOOP
dbms_output.put_line ( (i ) || '*' || (j ) || ('=') || (i*j) );
END LOOP;
END LOOP;
END;
/
And it brings back:
1*1=1
1*2=2
1*3=3
1*4=4
1*5=5
1*6=6
1*7=7
1*8=8
1*9=9
1*10=10
1*11=11
1*12=12
2*2=4
2*3=6
2*4=8
etc..
it brings back all the times tables like i wanted. Now i want it to bring back a title for each set, how would i do this? for e.g.
1 timetable
1*1=1
1*2=2
1*3=3
1*4=4
1*5=5
1*6=6
1*7=7
1*8=8
1*9=9
1*10=10
1*11=11
1*12=12
2 timestable
2*2=4
2*3=6
2*4=8
Is this possible?
Thanks

Try;
BEGIN
FOR i IN 1..12 LOOP
dbms_output.put_line(to_char(i) || ' timetable');
FOR j IN (i)..12 LOOP
dbms_output.put_line ( (i ) || '*' || (j ) || ('=') || (i*j) );
END LOOP;
END LOOP;
END;
/

Related

PL/SQL: Cursor doubles the last record from the table

I created the following PL/SQL anonymous block. The cursor below retrieves data from the select statement:
select mod_benutzer, count(*)
from dok_auspraegung
where parent_objekt_id = 1093
group by mod_benutzer;
This statement displays exactly two records:
DDMS_USER | 8
HU2MAMU | 14
But when I want to display these two records by cursor, it displays "HU2MAMU|14" two times like below:
Modifications:
DDMS_USER, 8x
HU2MAMU, 14x
HU2MAMU, 14x
declare
my_exception_1 exception;
var_parent_objekt_id dok_auspraegung.parent_objekt_id%TYPE := 1093;
var_date varchar(30);
var_mod_benutzer varchar2(10);
var_benutzer_modifs number;
cursor cursor_dok_auspraegung
is select mod_benutzer, count(*) from dok_auspraegung
where parent_objekt_id = 10935797565
group by mod_benutzer;
begin
select distinct to_char(mod_datum,'YYYY-MON-DD') into var_date from dok_auspraegung where parent_objekt_id = var_parent_objekt_id;
IF var_date is not null THEN
dbms_output.put_line('Parent Object ID' || ': ' || var_parent_objekt_id);
dbms_output.put_line('Date: ' || ' ' || var_date);
ELSE RAISE my_exception_1;
END IF;
open cursor_dok_auspraegung;
dbms_output.put_line('Modifications:');
loop
fetch cursor_dok_auspraegung into var_mod_benutzer, var_benutzer_modifs;
dbms_output.put(var_mod_benutzer);
dbms_output.put_line(', ' || var_benutzer_modifs || 'x');
exit when cursor_dok_auspraegung%notfound;
end loop;
dbms_output.put_line(cursor_dok_auspraegung%rowcount);
close cursor_dok_auspraegung;
exception
when NO_DATA_FOUND then
dbms_output.put_line('Parent Object ID not found!');
when my_exception_1 then
dbms_output.put_line('');
end;
What is the reason of that?
Because exiting from the cursor occurs after printing the value of the variables in the current case, this repeats the last value to be printed. So, it should occur before printing as follows
loop
fetch cursor_dok_auspraegung into var_mod_benutzer, var_benutzer_modifs;
exit when cursor_dok_auspraegung%notfound;
dbms_output.put(var_mod_benutzer);
dbms_output.put_line(', ' || var_benutzer_modifs || 'x');
end loop;

PL/SQL Variable parameters in procedure

I need to create a procedure that allows a user to input information for an order (which is below), but also for n number of suborders (where 2 ≤ n ≥ 10). How would I be able to incorporate this into the procedure I already have? I'm using SQLPlus. Any help or advice would be greatly appreciated. :)
CREATE OR REPLACE PROCEDURE VIEW_ORDER(ORDERS IN CHAR)
AS
CURSOR ORDER_CUR IS
SELECT * FROM SUBORDERS
WHERE ORDER_NO = ORDERS;
BEGIN
FOR O_REC IN ORDER_CUR
LOOP
DBMS_OUTPUT.PUT_LINE('Product Code: ' || O_REC.prod_id
|| ' Order: ' || O_REC.order_no
|| ' Suborder: ' || O_REC.suborder_no
|| ' Quantity: ' || O_REC.quantity);
END LOOP;
EXCEPTION
WHEN no_data_found THEN
DBMS_OUTPUT.PUT_LINE ('Product number does not exist');
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Operation failed ' || 'SQLCODE: ' || SQLCODE);
ROLLBACK;
END;
/
You can use for an input sqlplus command ACCEPT and make another loop to take n suborders.
If I didn't missunderstood your question it would be something like this:
-- You have to create the input outside the procedure
accept n char prompt 'Please enter n suborders: '
CREATE OR REPLACE PROCEDURE VIEW_ORDER(ORDERS IN CHAR)
AS
CURSOR ORDER_CUR IS
SELECT * FROM SUBORDERS
WHERE ORDER_NO = ORDERS;
BEGIN
FOR O_REC IN ORDER_CUR
LOOP
-- Here we check if n<=2
IF n>=2 THEN
-- here if n<=10
WHILE n<=10
LOOP
DBMS_OUTPUT.PUT_LINE('Product Code: ' || O_REC.prod_id
|| ' Order: ' || O_REC.order_no
|| ' Suborder: ' || O_REC.suborder_no
|| ' Quantity: ' || O_REC.quantity);
END LOOP;
END IF;
END LOOP;
EXCEPTION
WHEN no_data_found THEN
DBMS_OUTPUT.PUT_LINE ('Product number does not exist');
WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE ('Operation failed ' || 'SQLCODE: '
||
SQLCODE);
ROLLBACK;
END;
/

While Loop and If/Else in PL/SQL

I am trying to write a procedure that will produce the following output
exec WinOrLose(4)
Welcome to the Win or Lose Game. Your number is 4.
You win.
You lose.
You win.
You lose.
==> You lose!
So far I have this:
CREATE or REPLACE Procedure WinOrLose (
p_choice number ) AS
v_answer number;
DECLARE
v_answer := p_choice
BEGIN
dbms_output.put_line ('Welcome to the Win or Lose Game. Your number is ' ||
v_answer);
FOR v_answer in 1..10
IF MOD(v_answer, 2) = 0 THEN -- v_answer is even
dbms_output.put_line (You lose)
END;
/
I'm unsure of where to go from there. My thought process (psuedocode) is this:
SET v_answer := 1
While Loop (outside)
MOD(v_answer,2) = 0 then dbms.output (YOU LOSE)
ELSE
dbms.output (YOU WIN)
end if;
v_answer := p_choice
CREATE or REPLACE Procedure WinOrLose (
p_choice number ) AS
BEGIN
dbms_output.put_line ('Welcome to the Win or Lose Game. Your number is ' ||
p_choice);
FOR v_counter in 1..p_choice LOOP
IF (MOD(v_counter, 2) = 0)
THEN
dbms_output.put_line ('You win');
ELSE
dbms_output.put_line ('You lose');
END IF;
END LOOP;
IF (MOD(p_choice , 2) = 0)
THEN
dbms_output.put_line ('==> You win!');
ELSE
dbms_output.put_line ('==> You lose!');
END IF;
END;
/

Oracle pl/sql Change Array Size and Members After Delete

For example i have an array like
"a(1):=1 ,a(2):=2, a(3) := 3"
and now my array count =3 "(a.count)"
then i delete middle member "a.delete(2)" then i wanna make my array like this "a(1):=1;a(2):=3" and my array count = 2 ("a.count") how can i do this ?
ps:i need to this with big sized array so i think i should use, for or while loop but how...
The collection where you have deleted some element is called sparse collection. Below you have example how to iterate that type of collection and how to use it with forall.
declare
type a is table of number;
ar a;
v_idx number;
begin
select level bulk collect into ar from dual connect by level< 1000;
ar.delete(1);
ar.delete(4);
ar.delete(10);
ar.delete(88);
v_idx := ar.first;
while v_idx is not null loop
dbms_output.put_line('idx: '||v_idx ||' value:'|| ar(v_idx));
v_idx := ar.next(v_idx);
end loop;
-- FORALL i IN INDICES OF ar
-- INSERT INTO test_table VALUES ar(i);
end;
Thank you but i should change array too , i need to take same output when i print array members like
for i in ar.first..ar.last loop
dbms_output.put_line(ar(i));
end loop;
declare
type a is table of number;
ar a;
begin
select level bulk collect into ar from dual connect by level< 1000;
ar.delete(1);
ar.delete(4);
ar.delete(10);
ar.delete(88);
-- ar is sparse collection;
ar := ar MULTISET intersect ar;
-- ar is dense collection and for i in .... is possible
FOR i IN ar.first .. ar.last LOOP
DBMS_OUTPUT.put_line(ar(i));
END LOOP;
end;
you can try this approach assign values of first spared collection to second continues collection and use second collection for further processing...
declare
type num_arr is table of number;
v_num_arr1 num_arr; --first collection
v_num_arr2 num_arr := num_arr(); -- second collection initialization and declaration
v_idx number;
v_col_index number := 1;
begin
-- fill 10 element.
select level || '1' as num1 bulk collect into v_num_arr1 from dual connect by level < 10;
for x in v_num_arr1.first .. v_num_arr1.last loop
dbms_output.put_line('index: ' || x || ' value: ' || v_num_arr1(x));
end loop;
dbms_output.put_line('');
-- delete element
v_num_arr1.delete(3);
v_num_arr1.delete(7);
v_idx := v_num_arr1.first;
while v_idx is not null loop
dbms_output.put_line('index: ' || v_idx || ' value: ' || v_num_arr1(v_idx));
-- filling second collection with regular index by variable v_col_index
if v_num_arr1(v_idx) is not null then
v_num_arr2.extend(1);
v_num_arr2(v_col_index) := v_num_arr1(v_idx);
v_col_index := v_col_index + 1;
end if;
v_idx := v_num_arr1.next(v_idx);
end loop;
dbms_output.put_line('second collection elements
');
--check second colleciton
for x in v_num_arr2.first .. v_num_arr2.last loop
dbms_output.put_line('index: ' || x || ' value: ' || v_num_arr2(x));
end loop;
end;

Oracle : how to fetch data from dynamic query?

I have a program to generate dynamic query string based on input. This query may select from any tables or joined tables in my DB, and the column names and number of columns are unknown.
Now with this query string as the only input, I want to fetch all data from the result and output them line by line, is there any way to do this ?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Thank Thinkjet for the reference. I have solved the problem, to help the others, here is the piece of code I used:
DECLARE
v_curid NUMBER;
v_desctab DBMS_SQL.DESC_TAB;
v_colcnt NUMBER;
v_name_var VARCHAR2(10000);
v_num_var NUMBER;
v_date_var DATE;
v_row_num NUMBER;
p_sql_stmt VARCHAR2(1000);
BEGIN
v_curid := DBMS_SQL.OPEN_CURSOR;
p_sql_stmt :='SELECT * FROM emp';
DBMS_SQL.PARSE(v_curid, p_sql_stmt, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS(v_curid, v_colcnt, v_desctab);
-- Define columns:
FOR i IN 1 .. v_colcnt LOOP
IF v_desctab(i).col_type = 2 THEN
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_num_var);
ELSIF v_desctab(i).col_type = 12 THEN
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_date_var);
ELSE
DBMS_SQL.DEFINE_COLUMN(v_curid, i, v_name_var, 50);
END IF;
END LOOP;
v_row_num := dbms_sql.execute(v_curid);
-- Fetch rows with DBMS_SQL package:
WHILE DBMS_SQL.FETCH_ROWS(v_curid) > 0 LOOP
FOR i IN 1 .. v_colcnt LOOP
IF (v_desctab(i).col_type = 1) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_name_var);
ELSIF (v_desctab(i).col_type = 2) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_num_var);
ELSIF (v_desctab(i).col_type = 12) THEN
DBMS_SQL.COLUMN_VALUE(v_curid, i, v_date_var);
END IF;
END LOOP;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(v_curid);
END;
/
You can do that with DBMS_SQL package.
Update
To get more detailed reference about DBMS_SQL go here.
If you are building your string within PL/SQL, you can run it with EXECUTE IMMEDIATE. <- link. Use the BULK COLLECT INTO and output the collection.
<PRE>
DECLARE
RUN_S CLOB;
IGNORE NUMBER;
SOURCE_CURSOR NUMBER;
PWFIELD_COUNT NUMBER DEFAULT 0;
L_DESCTBL DBMS_SQL.DESC_TAB2;
Z_NUMBER NUMBER;
BEGIN
RUN_S := ' SELECT 1 AS VAL1,
2 AS VAL2,
CURSOR (SELECT 11 AS VAL11,
12 AS VAL12
FROM DUAL) AS CUR1,
CURSOR (SELECT 11 AS VAL11,
12 AS VAL12
FROM DUAL) AS CUR2
FROM DUAL';
SOURCE_CURSOR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(SOURCE_CURSOR, RUN_S, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(SOURCE_CURSOR, PWFIELD_COUNT, L_DESCTBL); -- get record structure
FOR I IN 1 .. PWFIELD_COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Col ' || I || ' Type:' || L_DESCTBL(I).COL_TYPE);
IF L_DESCTBL(I).COL_TYPE = 2 THEN
DBMS_SQL.DEFINE_COLUMN(SOURCE_CURSOR, I, Z_NUMBER);
END IF;
NULL;
END LOOP;
IGNORE := DBMS_SQL.EXECUTE(SOURCE_CURSOR);
LOOP
IF DBMS_SQL.FETCH_ROWS(SOURCE_CURSOR) > 0 THEN
FOR I IN 1 .. PWFIELD_COUNT LOOP
IF L_DESCTBL(I).COL_TYPE IN (2) THEN
DBMS_SQL.COLUMN_VALUE(SOURCE_CURSOR, I, Z_NUMBER);
DBMS_OUTPUT.PUT_LINE('Col ' || I || ' Value:' || Z_NUMBER);
END IF;
END LOOP;
ELSE
EXIT;
END IF;
END LOOP;
END;
</PRE>