How to get the summ of all values - oracle

I have this piece of code PL/SQL code in a procedure
for rec in(select t.val, t.cat from table t where a=1)
Loop
v:=(rec.val*rec.cat)/2;
end Loop;
How I can get the sum of all 'v' values?

This will create the sum in another variable, named tempSum
DECLARE
tempSum number (6);
tempSum := 0;
for rec in(select t.val, t.cat from table t where a=1)
Loop
v:=(rec.val*rec.cat)/2;
tempSum := tempSum + V;
end Loop;

Best way:
select sum(t.val * t.cat / 2) into l_val_cat_sum from table t where a = 1;

Related

TOP with index variable oracle

I was trying to use the variable 'ind' to get the ROWNUM on my select, but everytime I try to use the variable there I get a error like:
ORA-01008: not all variables bound
or these two:
ORA-01403: no data found
ORA-06512: at line 10
DECLARE
texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
LOOP
ind := ind + 1;
IF ind > 3 THEN
EXIT;
END IF;
SELECT TEXTO_LOG
INTO texto
from table WHERE REGEXP_LIKE(TEXTO_LOG, 'Alteração') AND ROWNUM >= :ind AND ROWNUM <= :ind ;
dbms_output.put_line(substr(trim(texto), 1, instr(texto, ' ')));
dbms_output.put_line(substr(texto, 0, 100));
END LOOP;
END;
/
I searched and found someone telling that not all variables bound is a bug, I'm not sure if it's.
I tried the ROWNUM with different opperators. Any suggestions?
Usage of rownum is the problem here apart from other issues already answered. a predicate like rownum>=2 and rownum <=2 (and so on...till exit point) yield no result and thus no_data_found error
But as workaround put the rownum inside from clause and restrict it outside should work,
DECLARE
texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
LOOP
ind := ind + 1;
IF ind > 3
THEN
EXIT;
END IF;
SELECT texto_log
INTO texto
FROM (SELECT texto_log
,rownum myrownum
FROM TABLE
WHERE regexp_like(texto_log
,'Alteração'))
WHERE myrownum >= ind
AND myrownum <= ind;
dbms_output.put_line(substr(TRIM(texto)
,1
,instr(texto
,' ')));
dbms_output.put_line(substr(texto
,0
,100));
END LOOP;
END;
/
The error is that you are referring to :ind as if it were a bind variable, when it is not. It is in fact a variable declared in your DECLARE section.
You might try this
** Update **
As your query looks like it is faling, the reason perhaps is in the query itself. Run this and get the output and running separately
set serveroutput on size unlimited
DECLARE
texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
for r in 1..4
LOOP
ind := r + 1;
dbms_output.put_line ( q'[SELECT TEXTO_LOG
INTO texto
from table WHERE REGEXP_LIKE(TEXTO_LOG, 'Alteração') AND ROWNUM <= ind ;
dbms_output.put_line(substr(trim(texto), 1, instr(texto, ' ')));
dbms_output.put_line(substr(texto, 0, 100));]');
exit when ind > 3;
END LOOP;
END;
/
Although you can build it like this which is easier
DECLARE
texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
for r in 1..4
LOOP
ind := r + 1;
dbms_output.put_line(ind);
SELECT TEXTO_LOG
INTO texto
from table WHERE REGEXP_LIKE(TEXTO_LOG, 'Alteração') AND ROWNUM >= ind AND ROWNUM <= ind ;
dbms_output.put_line(substr(trim(texto), 1, instr(texto, ' ')));
dbms_output.put_line(substr(texto, 0, 100));
exit when ind > 3;
END LOOP;
END;
/
EXample
SQL> DECLARE
texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
for r in 1..4
LOOP
ind := r + 1;
dbms_output.put_line(ind);
exit when ind > 3;
END LOOP;
END;
/ 2 3 4 5 6 7 8 9 10 11 12
2
3
4
PL/SQL procedure successfully completed.
SQL>
With implicit cursor
DECLARE
-- texto VARCHAR2(255);
ind NUMBER := 0;
BEGIN
FOR i IN (SELECT TEXTO_LOG FROM table WHERE REGEXP_LIKE(TEXTO_LOG, 'Alteração'))
LOOP
ind:=ind+1;
EXIT WHEN ind >3;
DBMS_OUTPUT.PUT_LINE(SUBSTR(TRIM(i.TEXTO_LOG), 1, INSTR(i.TEXTO_LOG, ' ')));
DBMS_OUTPUT.PUT_LINE(SUBSTR(i.TEXTO_LOG, 0, 100));
END LOOP;
END;

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!!

Reading two dimensional pl/sql array

I am able to insert values but failed to retrieve values. Thanks in anticipation.
declare
type type1 is table of number;
type data_type is table of type1;
y data_type;
begin
y := data_type();
y.extend(100);
for i in 1..100 loop
y(i) := type1();
y(i).extend(100);
for j in 1..100 loop
y(i)(j) := i+j;
end loop;
end loop;
end;
If I understand well, you need a way to scan your arrays;
this could be a way:
declare
type type1 is table of number;
type data_type is table of type1;
y data_type;
k number := 2;
begin
y := data_type();
y.extend(k);
for i in 1..k loop
y(i) := type1();
y(i).extend(k);
for j in 1..k loop
y(i)(j) := i+j;
end loop;
end loop;
-- scanning
for i in y.first .. y.last loop
for j in y(i).first .. y(i).last loop
dbms_output.put_line('Y(' || i || ')(' || j || ') = ' || y(i)(j));
end loop;
end loop;
end;
the result:
Y(1)(1) = 2
Y(1)(2) = 3
Y(2)(1) = 3
Y(2)(2) = 4

Algorithm name for all 2-uplets of a set

I'm looking for the name (and for the code : in PL/SQL or PG/SQL) of the algorithm which is finding all couple (2-uplets) of a set.
Example :
A - B - C
Result :
1 : A - B
2 : A - C
3 : B - C
I know that the powerset algorithm do this part of the job, but I'm looking for an optimised couple finder algorithm.
Link for the powerset pg/sql algorithm : https://www.postgresql.org/message-id/20060924054759.GA71934%40winnie.fuhr.org
Have you considered something like
Select A.x, B.x
From YourTable as A, YourTable as B
Where A.key <> B.key
You mention SQL so this might be preferable. Note that the number of rows in the cross product is about the same as the number of pairs, so it isn't terribly inefficient.
I've build the solution :
CREATE OR REPLACE FUNCTION twouplets(a anyarray)
RETURNS SETOF anyarray AS
$BODY$
DECLARE
retval a%TYPE;
size integer := array_upper(a, 1);
i integer;
j integer;
BEGIN
i := 0;
j := 1;
FOR i IN 1 .. size LOOP
FOR j IN 1 .. size-i LOOP
retval := '{}';
retval := array_append(retval, a[i]);
retval := array_append(retval, a[i+j]);
RETURN NEXT retval;
END LOOP;
END LOOP;
RETURN;
END;
$BODY$
LANGUAGE plpgsql IMMUTABLE STRICT
COST 100
ROWS 1000;
ALTER FUNCTION twouplets(anyarray)
OWNER TO postgres;

factorial of a number in pl/sql

The following pl/sql program generates an error on execution on line the sum :=temp*sum; encountered symbol ; when expecting ( . Please explain my mistake.
declare
n number;
temp number;
sum number := 1;
begin
n := &n;
temp := n;
while temp>0 loop
sum := temp*sum;
temp := temp-1;
end loop;
dbms_output.put_line('Factorial of '||n||' is '||sum);
end;
/
Maybe not the answer to your question, but there is no need for PL/SQL here:
select round(exp(sum(ln(level))))
from dual
connect by level <= 5;
where 5 is your number (5!).
Additionally, if you like to operate faster in PL/SQL use pls_integer instead of number.
UPDATE
So according to comments I felt free to test:
create or replace package test_ is
function by_query(num number) return number deterministic;
function by_plsql(num number) return number deterministic;
end test_;
/
create or replace package body test_ is
function by_query(num number) return number deterministic
is
res number;
begin
select round(exp(sum(ln(level))))
into res
from dual
connect by level <= num;
return res;
end;
function by_plsql(num number) return number deterministic
is
n number := 0;
begin
for i in 1..num loop
n := n + ln(i);
end loop;
return round(exp(n));
end;
end test_;
So there are two functions with different content. Test query:
declare
dummy number;
begin
for i in 1..10000 loop
dummy := test_.by_query(5);
end loop;
end;
0.094 sec.
declare
dummy number;
begin
for i in 1..10000 loop
dummy := test_.by_plsql(5);
end loop;
end;
0.094 sec.
You'll say I am cheater and using deterministic keyword but here it is obvious and is needed by logic. If I remove it, the same scripts are working 1.7 sec vs 1.3 sec, so procedure is only a bit faster, there is no even double-win in performance. The totally opposite effect you will get if you use the function in a query so it is a fair trade.
Sum is reserved word in sql. Change variable name like
declare
n number;
temp number;
sum_ number := 1;
begin
n := &n;
temp := n;
while temp>0 loop
sum_ := temp*sum_;
temp := temp-1;
end loop;
dbms_output.put_line('Factorial of '||n||' is '||sum_);
end;
/
declare
n number;
i number;
sum_of_log_10s number;
exponent number;
base number;
begin
n := &n;
i := 1;
sum_of_log_10s := 0;
while i <= n loop
-- do stuff
sum_of_log_10s := sum_of_log_10s + log(10,i);
i := i + 1;
end loop;
dbms_output.put_line('sum of logs = '||sum_of_log_10s);
exponent := floor(sum_of_log_10s);
base := power(10,sum_of_log_10s - exponent);
dbms_output.put_line(n||'! = '||base||' x 10^'||exponent);
end;
I came up with this code that I like even better than #smnbbrv's answer. It's a great way to check the speed of a machine. I've been using a variation of this since my Atari 800
ALTER SESSION FORCE PARALLEL DDL PARALLEL 16;
ALTER SESSION FORCE PARALLEL DML PARALLEL 16;
ALTER SESSION FORCE PARALLEL QUERY PARALLEL 16;
with t as (
select /*+materialize*/
rownum i
from dual connect by rownum < 100000 -- put number to calculate n! here
)
,t1 as (
select /*+parallel(t,16)*/ /*+materialize*/
sum(log(10,i)) logsum
from t
)
select
trunc(power(10,(mod(logsum,1))),3) ||' x 10^'||trim(to_char(floor(logsum),'999,999,999,999')) factorial
-- logsum
from t1
;
-- returns 2.824 x 10^456,568
Here is the simple code for finding factorial of number at run time...
declare
-- it gives the final answer after computation
fac number :=1;
-- given number n
-- taking input from user
n number := &1;
-- start block
begin
-- start while loop
while n > 0 loop
-- multiple with n and decrease n's value
fac:=n*fac;
--dbms_output.put(n||'*');
n:=n-1;
end loop;
-- end loop
-- print result of fac
dbms_output.put_line(fac);
-- end the begin block
end;

Resources