oracle show table like cartesian coordinate system - oracle

I have a table
create table test_table(
id number(10),
x number(10),
y number(10),
svalue number(10));
with filling a table as
declare
i integer;
begin
i := 0;
for x in 1 .. 10 loop
for y in 1 .. 10 loop
i := i + 1;
insert into test_table
(Id, x, y, svalue)
values
(i, x, y, x + y);
end loop;
end loop;
commit;
end;
how I can show table like
1 2 3 4 5 Ny
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6 7 8
Nx
where x - rows, y - columns, svalue - value x,y

if we want to get pivot output for Cartesian coordinate system
run below script for create pivot function
http://paste.ubuntu.com/21378705/
pivot function is actually ref cursor that give dynamic column output after ruining above script run query as
select * from table(pivot('select x,y,svalue from test_table'))
in above query select statement use as following manner
select rowsection,columnsection,data from table
i hope this will help.

Hear i achieve cartesian coordinate system using looping test_table.
declare
HEAD VARCHAR2(100);
CURSOR c1 IS SELECT distinct x rec FROM test_table order by x;
CURSOR c2 IS SELECT distinct y rec FROM test_table order by y;
begin
-- for disply header in y
for y in c2 loop
HEAD := HEAD || lpad(y.rec,4);
end loop;
DBMS_OUTPUT.put_line( lpad('X',3) || HEAD );
--
-- disply value with repect to x and y
for x in c1 loop
declare
STR VARCHAR2(100);
CURSOR c2 IS SELECT svalue rec FROM test_table where x= x.rec order by y;
begin
for y in c2 loop
STR := str || lpad(y.rec,4);
end loop;
DBMS_OUTPUT.put_line(lpad(x.rec,3) || STR);
end;
end loop;
--
end;
i hope this will help.

Related

bind variable not declared error when using procedure in pl/sql

`
declare
x number:=&x;
y number:=&y;
m number;
s1 number;
a1 number;
create or replace procedure z(x in number,y in number,m out number,s1 out number,a1 out number)
is
begin
if x<y
then
m:=x;
else
m:=y;
end if;
s1:=a+b;
a1:s1/2;
end z;
/
begin
z(x,y,m,s1,a1);
dbms_output.put_line('Sum:'||sum1);
end;
/
/
I am trying to find the min sum and average of 2 numbers inputted by the user using pl/sql procedure
You can't use things you didn't declare. Also, it is good to check for syntax errors.
See comments:
SQL> create or replace procedure z(x in number,y in number,m out number,s1 out number,a1 out number)
2 is
3 begin
4 if x<y
5 then
6 m:=x;
7 else
8 m:=y;
9 end if;
10 s1:=x+y; --> x and y not a and b
11 a1:=s1/2; --> := not just :
12 end z;
13 /
Procedure created.
Testing:
SQL> declare
2 x number:=&x;
3 y number:=&y;
4 m number;
5 s1 number;
6 a1 number;
7 begin
8 z(x,y,m,s1,a1);
9 dbms_output.put_line('Sum:'||s1); --> s1 not sum1
10 end;
11 /
Enter value for x: 3
Enter value for y: 5
Sum:8
PL/SQL procedure successfully completed.
SQL>

Print the sum of even digits of a number in Pl/sql

I cant seem to resolve this issue
As of the error itself, it is because you're trying to put the whole row (temp, which is declared as a cursor variable - c_nm%rowtype) into an integer variable (i). It won't work, although temp actually contains only one column - num.
So, line #15 on your screenshot:
No : i := temp;
Yes: i := temp.num;
Once you fix it, your code works but - unfortunately, produces wrong result. In input number 121974553, even digits are 2, 9, 4 and 5 whose sum equals 20, not 6 (as your result suggests):
SQL> set serveroutput on;
SQL> declare
2 ad int := 0;
3 i int;
4 b int;
5 cursor c_nm is select * From numb;
6 temp c_nm%rowtype;
7 begin
8 open c_nm;
9 loop
10 fetch c_nm into temp;
11 exit when c_nm%notfound;
12 i := temp.num; --> this
13
14 while i > 0 loop
15 b := mod(i, 10);
16 if mod(b, 2) = 0 then
17 ad := b + ad;
18 end if;
19 i := trunc(i/10);
20 end loop;
21 end loop;
22 dbms_output.put_line('ad = ' ||ad);
23 close c_nm;
24 end;
25 /
ad = 6
PL/SQL procedure successfully completed.
SQL>
A simpler option might be this: split number into digits (each in its separate row) so that you could apply SUM function to its even digits:
SQL> select * from numb;
NUM
----------
121974553 --> sum of even digits = 2 + 9 + 4 + 5 = 20
253412648 --> = 5 + 4 + 2 + 4 = 15
SQL> with
2 split as
3 -- split number into rows
4 (select num,
5 substr(num, column_value, 1) digit,
6 case when mod(column_value, 2) = 0 then 'Y'
7 else 'N'
8 end cb_odd_even
9 from numb cross join table(cast(multiset(select level from dual
10 connect by level <= length(num)
11 ) as sys.odcinumberlist))
12 )
13 -- final result: summary of digits in even rows
14 select num,
15 sum(digit)
16 from split
17 where cb_odd_even = 'Y'
18 group by num;
NUM SUM(DIGIT)
---------- ----------
253412648 15
121974553 20
SQL>
If it must be PL/SQL, slightly rewrite it as
SQL> declare
2 result number;
3 begin
4 for cur_r in (select num from numb) loop
5 with
6 split as
7 -- split number into rows
8 (select substr(cur_r.num, level, 1) digit,
9 case when mod(level, 2) = 0 then 'Y'
10 else 'N'
11 end cb_odd_even
12 from dual
13 connect by level <= length(cur_r.num)
14 )
15 -- final result: summary of digits in even rows
16 select sum(digit)
17 into result
18 from split
19 where cb_odd_even = 'Y';
20
21 dbms_output.put_line(cur_r.num || ' --> ' || result);
22 end loop;
23 end;
24 /
121974553 --> 20
253412648 --> 15
PL/SQL procedure successfully completed.
SQL>
You could do something like this. A few things of note: first, you can use an implicit cursor (the for rec in (select ...) loop construct). You don't need to declare the data type of rec, you don't need to open the cursor - and then remember to close it when you are finished - etc. Implicit cursors are a great convenience, best to learn about it as early as possible. Second, note that rec (in my notation) is just a pointer; to access the value from it, you must reference the table column (as in, rec.num) - Littlefoot has already shown that in his reply. Third, a logic mistake in your attempt: if the table has more than one row, you must initialize ad to 0 for each new value - you can't just initialize it to 0 once, at the beginning of the program.
So, with all that said - here is some sample data, then the procedure and its output.
create table numb (num int);
insert into numb values(121975443);
insert into numb values(100030000);
insert into numb values(null);
insert into numb values(113313311);
insert into numb values(2020);
commit;
. . . . .
declare
ad int;
i int;
begin
for rec in (select num from numb) loop
ad := 0;
i := rec.num;
while i > 0 loop
if mod(i, 2) = 0 then
ad := ad + mod(i, 10);
end if;
i := trunc(i/10);
end loop;
dbms_output.put_line('num: ' || nvl(to_char(rec.num), 'null') ||
' sum of even digits: ' || ad);
end loop;
end;
/
num: 121975443 sum of even digits: 10
num: 100030000 sum of even digits: 0
num: null sum of even digits: 0
num: 113313311 sum of even digits: 0
num: 2020 sum of even digits: 4
PL/SQL procedure successfully completed.

how to define multiple (WITH AS FUNCTIONS) in a single query?

trying to define multiple functions under a single with clause. which we normally do for CTE's. But for functions the same is not working. Please suggest solutions please.
With function dt ( b as number)
return number is
n number ;
begin
select 1 into n;
return n ;
end ;
dt2 ( c as number)
return number is
n1 number ;
begin
select 1 into n;
return n1;
end ;
select dt(1) , dt2(1) from dual
when using only dt i am able to get o/p but not with dt2.
It is working with the following example:
with
function x(p_NUM in number) return number
is
n number;
begin
SELECT 1 INTO N FROM DUAL;
--
return N;
--
end ;
--
function Y(p_NUM in number) return number
is
N1 NUMBER;
begin
SELECT 2 INTO N1 FROM DUAL;
--
return N1;
--
end ;
--
select X(1), Y(1)
from dual;
Cheers!!

Progressive LOOP Statement ORACLE

How to create a function that returns a float(ChargeTotal)?
ChargeTotal is based on a progressive table using number of batches.
num of batches | charge
----------------------------
1-10 | 0
11-20 | 50
21-30 | 60
31-40 | 70
40+ | 80
If number of batches is 25 then
num of batches | charge
----------------------------
1-10 | 0
11-20 | 50*10
21-30 | 60*5
----------------------------
total | 800 <number I need to be returned(ChargeTotal)
So far I have come up with the following, but I'm unsure how to get the total for each loop, or if it is even possible to do more than one FOR statements:
CREATE OR REPLACE FUNCTION ChargeTotal
RETURN FLOAT IS
total FLOAT;
BEGIN
FOR a in 1 .. 10 LOOP
FOR a in 11 .. 20 LOOP
FOR a in 21 .. 30 LOOP
FOR a in 40 .. 1000 LOOP
RETURN Total;
END ChargeTotal;
Ok so take into consideration that right now I have no DB available to test this (there might be some syntax errors etc).
But I am thinking something along this lines of code...
function ChargeTotal(xin number) return number is
cursor mycursor is
select lowLimit,highLimit,charge
from progressive_table order by lowLimit;
sum number;
segment number;
x number;
begin
sum:=0;
x :=xin;
for i in mycursor loop
segment := (i.highLimit-i.lowLimit)+1;
x := greatest ( x - segment,x);
sum := sum + segment*i.charge;
if (x<segment) then
return sum;
end if;
end loop;
return sum;
end;
I think you can do the calculation via single sql without complex function
the logic is:
you have weights for each "band"
calculate the "band" each row
count(*) over to calculate number of rows in each "band"
join your weight table to get sub.total for each band
use rollup to get grand total
sql
select r.num_of_batches
,sum(r.subtotal_charge)
from (
with weights as
(select 1 as num_of_batches, 0 as charge from dual
union all
select 2 as num_of_batches, 50 as charge from dual
union all
select 3 as num_of_batches, 60 as charge from dual
union all
select 4 as num_of_batches, 70 as charge from dual
union all
select 5 as num_of_batches, 80 as charge from dual
)
select distinct n.num_of_batches
, w.charge
, count(*) over (partition by n.num_of_batches) as cnt
, count(*) over (partition by n.num_of_batches) * charge as subtotal_charge
from (
select num, case when floor(num / 10) > 4 then 5 else floor(num / 10)+1 end as num_of_batches
from tst_brances b
) n
inner join weights w on n.num_of_batches = w.num_of_batches
order by num_of_batches
) r
group by ROLLUP(r.num_of_batches)
populate test data
create table tst_branches(num int);
declare
i int;
begin
delete from tst_brances;
for i in 1..10 loop
insert into tst_brances(num) values (i);
end loop;
for i in 11..20 loop
insert into tst_brances(num) values (i);
end loop;
for i in 21..25 loop
insert into tst_brances(num) values (i);
end loop;
for i in 31..32 loop
insert into tst_brances(num) values (i);
end loop;
for i in 41..43 loop
insert into tst_brances(num) values (i);
end loop;
for i in 51..55 loop
insert into tst_brances(num) values (i);
end loop;
commit;
end;
results
1 1 0
2 2 500
3 3 360
4 4 140
5 5 640
6 1640

How to create two variables refering the same nested table?

I expected that in the following code variables x and y refer the same nested table object but expression y = x seems to create empty table in y. So output is surprisingly 'No: a c' ( however I expected 'Yes: a b c'). What should I do in PL/SQL to have y referring the same nested table object as x.
declare
type str_t is table of varchar(100);
x str_t := str_t ();
y str_t ;
begin
x.extend; x(x.last) := 'a';
y := x;
y.extend; y(y.last) := 'b';
x.extend; x(x.last) := 'c';
dbms_output.put_line(case when x=y then 'Yes: ' else 'No: ' end);
for i in x.first .. x.last
loop
dbms_output.put_line(x(i));
end loop;
Сan it (passing nested table by reference - not by value) be written in PL/SQL or it's fundamentally impossible? Does any alternatives exist in the language to aviod the problem?
PL/SQL doesn't have references (but in one place we'll see later) so essentially what you're asking is impossible in PL/SQL. I don't see how that can be a problem, though.
In your example x and y are two different variables that are having the same type (a nested table collection), x := y is a variable assigment (deep copy), x = y is a comparison. See also e.g. Assigning Values to Variables.
I guess you've programming background with some other languages and you're trying to apply some other language paradigm here. You also might have an XY-problem.
One alternative is to use two different index variables to access the collection. That might or might not suit for your case:
declare
type str_list_t is table of varchar2(32767);
v_foos constant str_list_t := str_list_t('a', 'b', 'c');
-- have some business logic to get the right indices
i pls_integer := 1;
j pls_integer := 3;
begin
dbms_output.put_line(v_foos(i));
dbms_output.put_line(v_foos(j));
end;
/
But please note that changes to collection will invalidate the index variables (that's why I declared a constant collection).
When working with nested tables check also SQL multiset conditions that provide a powerful manipulations.
The only place with reference semantics is subprogram parameters where different parameter modes (IN, OUT or IN OUT) have different semantics (pass-by-value or pass-by-reference). But even there the decision is made by PL/SQL compiler/runtime - programmer has no much control.
So output is surprisingly 'No: a c' ( however I expected 'Yes: a b c').
Your expectation is wrong. Since the two arrays are having different values.
Let's see step by step:
x.extend;
x(x.last) := 'a';
So, x has value a.
y := x;
x is copied to y, so y has value a.
y.extend;
y(y.last) := 'b';
Now, y has a and b.
x.extend;
x(x.last) := 'c';
Now, x has a and c.
Finally,
X --> a,c
Y --> a,b
Let's see what your code shows the output:
SQL> set serveroutput on
SQL> DECLARE
2 type str_t
3 IS
4 TABLE OF VARCHAR(100);
5 x str_t := str_t ();
6 y str_t ;
7 BEGIN
8 x.extend;
9 x(x.last) := 'a';
10 y := x;
11 y.extend;
12 y(y.last) := 'b';
13 x.extend;
14 x(x.LAST) := 'c';
15 FOR i IN x.first .. x.last
16 LOOP
17 dbms_output.put_line('X'||'-'||x(i));
18 END LOOP;
19 FOR i IN y.first .. y.last
20 LOOP
21 dbms_output.put_line('Y'||'-'||y(i));
22 END LOOP;
23 END;
24 /
X-a
X-c
Y-a
Y-b
PL/SQL procedure successfully completed.
SQL>
So, X and Y are not equal.
To make them equal, set Y = X:
SQL> set serveroutput on
SQL> DECLARE
2 type str_t
3 IS
4 TABLE OF VARCHAR(100);
5 x str_t := str_t ();
6 y str_t ;
7 BEGIN
8 x.extend;
9 x(x.LAST) := 'a';
10 x.extend;
11 x(x.last) := 'b';
12 x.extend;
13 x(x.LAST) := 'c';
14 y := x;
15 dbms_output.put_line(case when x=y then 'Yes: ' else 'No: ' end);
16 FOR i IN x.first .. x.last
17 LOOP
18 dbms_output.put_line('X'||'-'||x(i));
19 END LOOP;
20 END;
21 /
Yes:
X-a
X-b
X-c
PL/SQL procedure successfully completed.
SQL>

Resources