Updating multiple columns with function call - oracle

Supposing I have table with columns
a, b, c, d, e
Is there a way/syntax to update columns d and e from out parameters of procedure/function that takes in parameters values of columns a, b and c. (procedure(a, b, c, out d, out e))
(other than using a cursor to iterate through all rows one by one)?

You could create a PL/SQL tables or user defined records, like so
Function to process records
FUNCTION Get_updated_recs(p_emp_id emp.emp_id%TYPE,
p_manager_id emp.manager_id%TYPE)
RETURN EMP_REC_TYPE
IS
p_emp_rec EMP_REC_TYPE;
BEGIN
IF p_emp_id = 100 THEN
p_emp_rec.salary := 50000;
p_emp_rec.bonus := 10000;
END IF;
RETURN p_emp_rec;
END get_updated_recs;
Main program unit
DECLARE
TYPE emp_rec_type IS RECORD (
salary employees.salary%TYPE,
bonus employees.bonus );
emp_rec EMP_REC_TYPE;
BEGIN
FOR emp IN (SELECT *
FROM employees) LOOP
emp_rec := Get_updated_recs(emp.emp_id, emp.manager_id);
UPDATE employees
SET salary = emp_rec.salary,
bonus = emp_rec.bonus
WHERE emp_id = emp.emp_id;
END LOOP;
END;
I haven't tested/compiled it, just wrote out of my memory but something like this should work

With help of an Oracle expert I arrived at following solution:
CREATE TABLE testtable
(
a number,
b number,
c number,
d number
);
CREATE TYPE testobj AS OBJECT
(
x number,
y number
);
CREATE OR REPLACE FUNCTION testfun(a number, b number)
RETURN testobj IS
begin
return new testobj(x=>a+b, y=> a*b);
end;
INSERT INTO testtable VALUES (1,2,null,null);
INSERT INTO testtable VALUES (5,6,null,null);
UPDATE
(SELECT tt.*,
testfun1(a,b) fun_ret FROM testtable tt) talias
SET talias.c=talias.fun_ret.x,
talias.d=talias.fun_ret.y
;

Do as follows:
(1) Create and fill an example table:
CREATE TABLE TEST1
(
a NUMBER(10), b number (10), s number (10)
);
INSERT INTO TEST1 (a, b, s) VALUES (2, 3, NULL);
INSERT INTO TEST1 (a, b, s) VALUES (3, 12, NULL);
INSERT INTO TEST1 (a, b, s) VALUES (-2, 8, NULL);
(2) Create a simple function for the using in an UPDATE command:
CREATE OR REPLACE FUNCTION GET_SUM (x IN NUMBER, y IN NUMBER)
RETURN NUMBER
IS
x1 NUMBER(10) := x; y1 NUMBER (10):= y; s NUMBER(10) := NULL;
BEGIN
IF x1 IS NOT NULL AND y1 IS NOT NULL THEN s := x1 + y1; END IF;
RETURN s;
END;
(3) Use this function in the following UPDATE command:
UPDATE TEST1 SET s = GET_SUM (a, b);
(4) Check the updates:
select * from TEST1;

Related

How to I add a constant into a with block?

In a with block, I can define function and query, I would like to define a constant too that I can reuse after.
the following code works.
WITH
FUNCTION a (a IN INTEGER)
RETURN INTEGER
IS
BEGIN
RETURN a + 1;
END;
b(v) AS (SELECT column_value FROM sys.ODCINUMBERLIST(1,2,3))
SELECT a (v) FROM b;
but this doesn't work.
WITH
c integer:=1;
FUNCTION a (a IN INTEGER)
RETURN INTEGER
IS
BEGIN
RETURN a + 1;
END;
b(v) AS (SELECT column_value FROM sys.ODCINUMBERLIST(1,2,3))
SELECT a (v) FROM b;
[Error] Execution (14: 20): ORA-00942: table or view does not exist
I know that I can create another query in the with block:
select 1 c from dual
But it doesn't look pretty if I have a lot of constants.
Is there a way to add constant in a with block?
Add another subquery factoring clause with exactly one row and define all the constants in there and then CROSS JOIN it to your other queries:
WITH FUNCTION a (a IN INTEGER)
RETURN INTEGER
IS
BEGIN
RETURN a + 1;
END;
constants (c1, c2, c3, c4) AS (
SELECT 1, 2, 3, 4 FROM DUAL
),
b(v) AS (
SELECT column_value FROM sys.ODCINUMBERLIST(1,2,3)
)
SELECT a(v), c.*
FROM b
CROSS JOIN constants c;
Or, you could declare a function for each constant:
WITH FUNCTION a (a IN INTEGER)
RETURN INTEGER
IS
BEGIN
RETURN a + 1;
END;
FUNCTION c1 RETURN INTEGER IS BEGIN RETURN 1; END;
FUNCTION c2 RETURN INTEGER IS BEGIN RETURN 2; END;
FUNCTION c3 RETURN INTEGER IS BEGIN RETURN 3; END;
FUNCTION c4 RETURN INTEGER IS BEGIN RETURN 4; END;
b(v) AS (
SELECT column_value FROM sys.ODCINUMBERLIST(1,2,3)
)
SELECT a(v), c1, c2, c3, c4
FROM b;
(However, using functions may introduce a performance overhead with repeated context-switches between SQL and PL/SQL scopes. Personally, I would use the first option.)
Which both output:
A(V)
C1
C2
C3
C4
2
1
2
3
4
3
1
2
3
4
4
1
2
3
4
db<>fiddle here

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

oracle show table like cartesian coordinate system

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.

How to get the summ of all values

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;

In Cassandra how to select rows by multiple filters?

I have a table like below:
CREATE TABLE test ( a int; b int; c int; d int; PRIMARY KEY () );
I want to select the data with 0 < a < 10 and 0 < b < 10, how should I set the PRIMARY KEY and how should I run the CQL query?
Thanks!
Using range operators (< >) on the partitioning key is not allowed unless you use the ByteOrderedPartitioner which has several drawbacks related to performance.
Else, with the default Murmur3Partitioner, you have two options. First solution:
create table test (
a int,
b int,
c int,
d int,
primary key ((a,b))
);
Then for X in 1..10
select * from test where a = X and b in (1,2,3,4,5,6,7,8,9,10)
Second solution:
create table test (
a int,
b int,
c int,
d int,
primary key (a,b)
);
Then
select * from test where a in (1,2,3,4,5,6,7,8,9,10) and b >=1 and b <= 10 ;

Resources