Oracle aggregate functions and how to concatenate all values in column - sql

All,
My Oracle Database is version 10g Enterprise Edition Release 10.2.0.5.0 - 64bit
I have the following statement which usefully gets me the max (or min or count etc) values in each case as expected however what I would like is to get and to concatenate all of the values rather than the max, min or count - is there an elegant way to do this please ?
SELECT lla.id,
max(decode(lla.attrid, 2, lla.valstr, null)) "Attribute Name 2",
min(decode(lla.attrid, 3, lla.valstr, null)) "Attribute Name 3",
count(decode(lla2.attrid, 5, lla2.valstr, null)) "Attribute Name 5"
FROM llattrdata lla, llattrdata lla2
WHERE lla.id = lla2.id
AND lla.defid = 111111 --category id 1
AND lla2.defid = 222222 --category id 2
AND lla.id = 48212327 and lla2.id = 48212327
GROUP BY lla.id
Hoping for a row that looks something like this:
12121212 | fred, jack, gill | 56 | 29,10
To be clearer it is the values that the 'Attribute Name 3' (for example) contains that I want to see all of and not just the max or the minimum. In other words for that attribute I can get the max or the min value or even the count but cannot see a way to get all of the values ? In other words I can get 10 as the min and 29 as the max - even 2 as the count but not 29 and 10 in the same column !
Many thanks in advance,

SELECT e.department_id,
listagg(e.first_name) within group (order by e.department_id) "Attribute Name 2"
FROM employees e join
departments d
on e.department_id = d.department_id
GROUP BY e.department_id;
you can use above example and alter your query

Try this:
SELECT lla.id || ' | ' ||
max(decode(lla.attrid, 2, lla.valstr, null)) || ' | ' ||
min(decode(lla.attrid, 3, lla.valstr, null)) || ' | ' ||
count(decode(lla2.attrid, 5, lla2.valstr, null))
FROM llattrdata lla, llattrdata lla2
WHERE lla.id = lla2.id
AND lla.defid = 111111 --category id 1
AND lla2.defid = 222222 --category id 2
AND lla.id = 48212327 and lla2.id = 48212327
GROUP BY lla.id

Use wmsys.wm_concat function learn more here about it. This is a non-documented function in Oracle 10.
It returns you comma-separated list, you can use replace function to replace comma with the thing you need.
Unfortunately this function does not have order clause so you cannot specify the order in the list.
EDIT:
As far as this function is not available for you, you can simply create it:
CREATE OR REPLACE TYPE wm_concat_impl
AUTHID CURRENT_USER
AS OBJECT (
curr_str VARCHAR2 (32767),
STATIC FUNCTION odciaggregateinitialize (sctx IN OUT wm_concat_impl)
RETURN NUMBER,
MEMBER FUNCTION odciaggregateiterate (
SELF IN OUT wm_concat_impl,
p1 IN VARCHAR2
)
RETURN NUMBER,
MEMBER FUNCTION odciaggregateterminate (
SELF IN wm_concat_impl,
returnvalue OUT VARCHAR2,
flags IN NUMBER
)
RETURN NUMBER,
MEMBER FUNCTION odciaggregatemerge (
SELF IN OUT wm_concat_impl,
sctx2 IN wm_concat_impl
)
RETURN NUMBER
);
/
CREATE OR REPLACE TYPE BODY wm_concat_impl
IS
STATIC FUNCTION odciaggregateinitialize (sctx IN OUT wm_concat_impl)
RETURN NUMBER
IS
BEGIN
sctx := wm_concat_impl (NULL);
RETURN odciconst.success;
END;
MEMBER FUNCTION odciaggregateiterate (
SELF IN OUT wm_concat_impl,
p1 IN VARCHAR2
)
RETURN NUMBER
IS
BEGIN
IF (curr_str IS NOT NULL)
THEN
curr_str := curr_str || ',' || p1;
ELSE
curr_str := p1;
END IF;
RETURN odciconst.success;
END;
MEMBER FUNCTION odciaggregateterminate (
SELF IN wm_concat_impl,
returnvalue OUT VARCHAR2,
flags IN NUMBER
)
RETURN NUMBER
IS
BEGIN
returnvalue := curr_str;
RETURN odciconst.success;
END;
MEMBER FUNCTION odciaggregatemerge (
SELF IN OUT wm_concat_impl,
sctx2 IN wm_concat_impl
)
RETURN NUMBER
IS
BEGIN
IF (sctx2.curr_str IS NOT NULL)
THEN
SELF.curr_str := SELF.curr_str || ',' || sctx2.curr_str;
END IF;
RETURN odciconst.success;
END;
END;
/
CREATE OR REPLACE FUNCTION wm_concat (p1 VARCHAR2)
RETURN VARCHAR2
AGGREGATE USING wm_concat_impl;
/
The query is taken from this website, it is, unfortunately, in Russian, but just use this custom aggregate function for your purposes.

I had the same problem and used the STRAGG ( as in STRing AGGregate) function created by Tom Kyte.
https://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:15637744429336
create or replace type stragg_type as object
(
string varchar2(4000),
static function ODCIAggregateInitialize
( sctx in out stragg_type )
return number ,
member function ODCIAggregateIterate
( self in out stragg_type ,
value in varchar2
) return number ,
member function ODCIAggregateTerminate
( self in stragg_type,
returnvalue out varchar2,
flags in number
) return number ,
member function ODCIAggregateMerge
( self in out stragg_type,
ctx2 in stragg_type
) return number
);
/
create or replace type body stragg_type
is
static function ODCIAggregateInitialize
( sctx in out stragg_type )
return number
is
begin
sctx := stragg_type( null ) ;
return ODCIConst.Success ;
end;
member function ODCIAggregateIterate
( self in out stragg_type ,
value in varchar2
) return number
is
begin
self.string := self.string || ',' || value ;
return ODCIConst.Success;
end;
member function ODCIAggregateTerminate
( self in stragg_type ,
returnvalue out varchar2 ,
flags in number
) return number
is
begin
returnValue := ltrim( self.string, ',' );
return ODCIConst.Success;
end;
member function ODCIAggregateMerge
( self in out stragg_type ,
ctx2 in stragg_type
) return number
is
begin
self.string := self.string || ctx2.string;
return ODCIConst.Success;
end;
end;
/
create or replace function stragg
( input varchar2 )
return varchar2
deterministic
parallel_enable
aggregate using stragg_type
;
/
Run the three create statements one after the other in sqlplus or sqldev. Now the stragg() function is created in your user schema. Then you can do:
SELECT lla.id,
max(decode(lla.attrid, 2, lla.valstr, null)) "Attribute Name 2",
STRAGG(decode(lla.attrid, 3, lla.valstr, null)) "Attribute Name 3 List",
count(decode(lla2.attrid, 5, lla2.valstr, null)) "Attribute Name 5"
FROM llattrdata lla, llattrdata lla2
WHERE lla.id = lla2.id
AND lla.defid = 111111 --category id 1
AND lla2.defid = 222222 --category id 2
AND lla.id = 48212327 and lla2.id = 48212327
GROUP BY lla.id

Related

Boolean return value of some function inside SELECT

I am working on a package in PL/SQL.
This is my spec:
TYPE outrec IS RECORD(
tw_m_id NUMBER,
tw_m_dealer_id NUMBER,
tw_number NUMBER,
check_uid NUMBER);
TYPE outrecset IS TABLE OF outrec;
FUNCTION report
(
p_watermark IN NUMBER,
p_param IN NUMBER,
p_index IN NUMBER
) RETURN outrecset
PIPELINED;
This is my body:
FUNCTION func
(
p_watermark => p_watermark,
p_param => p_param,
p_index => p_index
)
RETURN outrecset
PIPELINED IS
temp outrec;
BEGIN
before_report(p_watermark => p_watermark,
p_param => p_param,
p_index => p_index);
FOR c_rec IN (SELECT tw_m_id,
tw_m_dealer_id,
tw_number,
package_name.somefunction(tw_number) AS check_uid
FROM table1
JOIN table2 rk ON id1 = rk.id2
WHERE 1 = 1
AND id1 = rk.id2
AND id1 = p_param)
LOOP
temp.tw_m_tw_rechnungskopf_id := c_rec.tw_m_tw_rechnungskopf_id;
temp.tw_m_haendler_id_rechnung := c_rec.tw_m_haendler_id_rechnung;
temp.check_uid := c_rec.check_uid;
PIPE ROW(temp);
END LOOP;
END;
I am trying to get value from package_name.somefunction(tw_number) AS check_uid. The problem is that somefunction returns BOOLEAN value.
When I set check_uid to BOOLEAN I get Error: PLS-00382: expression is of the wrong type because of course SQL doesn't support BOOLEAN. I tried :
CASE
WHEN package_name.somefunction(tw_number) THEN true
else false
END as check_uid
inside SELECT then I get Error: PL/SQL: ORA-00920: invalid relational operator.
Can someone tell me how to do this PL/SQL is not my strongest side :(
EDIT: I can't change somefunction to return for an example varchar2 it needs to stay the way it is
Write a simple wrapper function to convert the PL/SQL BOOLEAN to a NUMBER data type that is valid in SQL and expected by your record type and you can move the function call outside the SQL.
CREATE FUNCTION MAP_BOOLEAN( truthy IN BOOLEAN ) RETURN NUMBER DETERMINISTIC
IS
BEGIN
RETURN CASE truthy
WHEN TRUE THEN 1
WHEN FALSE THEN 0
ELSE NULL
END;
END map_boolean;
/
So your specification would be:
CREATE PACKAGE package_name IS
TYPE outrec IS RECORD(
tw_m_id NUMBER,
tw_m_dealer_id NUMBER,
tw_number NUMBER,
check_uid NUMBER
);
TYPE outrecset IS TABLE OF outrec;
-- Note: This may be in another package but is here for convenience.
FUNCTION somefunction(value IN NUMBER) RETURN BOOLEAN;
FUNCTION report
(
p_watermark IN NUMBER,
p_param IN NUMBER,
p_index IN NUMBER
) RETURN outrecset PIPELINED;
END;
/
and the corresponding body would be:
CREATE PACKAGE BODY package_name IS
FUNCTION somefunction(value IN NUMBER) RETURN BOOLEAN
IS
BEGIN
RETURN TRUE;
END;
PROCEDURE before_report(
p_watermark IN NUMBER,
p_param IN NUMBER,
p_index IN NUMBER
)
IS
BEGIN
NULL;
END;
FUNCTION report(
p_watermark IN NUMBER,
p_param IN NUMBER,
p_index IN NUMBER
) RETURN outrecset PIPELINED
IS
temp outrec;
BEGIN
before_report(
p_watermark => p_watermark,
p_param => p_param,
p_index => p_index
);
FOR c_rec IN (
SELECT tw_m_id,
tw_m_dealer_id,
tw_number
FROM table1
JOIN table2 rk ON id1 = rk.id2
WHERE id1 = p_param
)
LOOP
temp.tw_m_id := c_rec.tw_m_id;
temp.tw_m_dealer_id := c_rec.tw_m_dealer_id;
temp.check_uid := MAP_BOOLEAN(
PACKAGE_NAME.SOMEFUNCTION( c_rec.tw_number )
);
PIPE ROW(temp);
END LOOP;
END;
END;
/
(Note: you also need to update the cursor loop as the values you were selecting did not match the fields of the record.)
db<>fiddle here
Typically you would create an overloaded function in your package that returns 1/0 or Y/N. But since you have no access to the package you can use an inline function in your sql query to do this for you.
create or replace function func (parameter_i VARCHAR2) RETURN BOOLEAN
AS
BEGIN
return true;
END;
/
WITH
FUNCTION func_yn(parameter_i VARCHAR2)
RETURN NUMBER
IS
l_return_value BOOLEAN;
BEGIN
l_return_value :=func(parameter_i => parameter_i);
RETURN CASE l_return_value WHEN TRUE THEN 1 WHEN FALSE THEN 0 END;
END func_yn;
SELECT
func_yn('test')
FROM dual;

Assign ref variable value oracle

hHey,
I want to set the value of the assignment value in the method of the node_ty. However I get the error that navigation through Ref variables is not allowed or the typ I want to assign is not correct. So I don't really know how to do that. Could you help me with that?
CREATE OR REPLACE TYPE property_ty AS OBJECT(
name VARCHAR2(100)
);
/
CREATE OR REPLACE TYPE assignment_ty AS OBJECT(
value VARCHAR2(100),
property REF property_ty
);
/
CREATE OR REPLACE TYPE property_tty AS TABLE OF property_ty;
/
CREATE OR REPLACE TYPE node_ty AS OBJECT(
x NUMBER,
y NUMBER,
assignment REF assignment_ty,
property property_tty,
MEMBER PROCEDURE set_assignment (name VARCHAR2, value VARCHAR2)
);
/
CREATE OR REPLACE TYPE BODY node_ty AS
MEMBER PROCEDURE set_assignment (name VARCHAR2, value VARCHAR2) AS
prop_not_added EXCEPTION;
prop_exists BOOLEAN := FALSE;
assig_test assignment_ty;
prop property_ty;
BEGIN
FOR i IN 1..self.property.COUNT
LOOP
IF property(i).name = name THEN
prop.name :=name;
assig_test.value :=value;
assig_test.property := prop;
assignment := assig_test;
prop_exists := TRUE;
END IF;
END LOOP;
IF prop_exists = FALSE THEN
RAISE prop_not_added;
END IF;
EXCEPTION
WHEN prop_not_added THEN
DBMS_OUTPUT.PUT_LINE('Property cannot be set');
END;
END;
/
You have to create the necessary setup and then query the data from the setup.I am giving only the setup which is different from yours.The remaining you can keep it as same as your setup
create table t00 of property_ty;
insert into t00 values('san');
create table t0 of assignment_ty;
insert into t0 select 'xxx',REF(p) from t00 p;
CREATE OR REPLACE TYPE node_ty AS OBJECT(
x NUMBER,
y NUMBER,
assignment REF assignment_ty,
property property_tty,
MEMBER PROCEDURE set_assignment (p_name VARCHAR2, p_value VARCHAR2)
);
create or replace TYPE BODY node_ty AS
MEMBER PROCEDURE set_assignment (p_name VARCHAR2, p_value VARCHAR2) AS
prop_not_added EXCEPTION;
prop_exists BOOLEAN := FALSE;
assig_test REF assignment_ty;
prop1 property_ty;
prop REF property_ty;
BEGIN
FOR i IN 1..self.property.COUNT
LOOP
IF property(i).name = p_name THEN
SELECT REF(a) INTO assignment FROM t0 a,t00 b where a.value=p_value and b.name=p_name
and ref(b)=property;
prop_exists := TRUE;
END IF;
END LOOP;
IF prop_exists = FALSE THEN
RAISE prop_not_added;
END IF;
EXCEPTION
WHEN prop_not_added THEN
DBMS_OUTPUT.PUT_LINE('Property cannot be set');
END;
END;

Oracle - object order - how does it work?

Oracle doc says as follows: "As with map methods, an order method, if one is defined, is called automatically whenever two objects of that type need to be compared."
So I assume it will sort when using 'order by' clausule.
Lets say, I have following object:
create or replace type height as object
(
val number,
constructor function height return self as result,
constructor function height (val number) return self as result,
order member function compare (other height) RETURN INTEGER
);
and its body implementation:
create or replace type body height is
constructor function height return self as result is
begin
self.val := null;
end;
constructor function height (val number) return self as result is
begin
self.val := val;
return;
end;
order member function compare (other height) return integer is
begin
if self.val > self.val then return 1;
elsif self.val < self.val then return -1;
else return 0;
end if;
end;
end;
Then my table looks like this:
CREATE TABLE people (
name varchar2(50),
height height
);
And some records ...
insert into people values ('Foo', height(150));
insert into people values ('Bar', height(130));
insert into people valueS ('Baz', height(180));
Then I want to sort it:
select p.height.val from people p order by height ASC;
select p.height.val from people p order by height DESC;
But result is the same for 2 queries, no matter if order is asc or desc.
I experimented with your code and found a solution.
The solution that works looks like this
I have added a second compare function with two parameters
create or replace type height as object
(
val number,
constructor function height return self as result,
constructor function height (val number) return self as result,
order member function compare2 (other height) return integer,
member function compare (o1 height,o2 height) return integer
);
/
create or replace type body height is
constructor function height return self as result is
begin
self.val := null;
end;
constructor function height (val number) return self as result is
begin
self.val := val;
return;
end;
order member function compare2 (other height) return integer is
begin
RETURN compare(SELF,other);
end;
member function compare (o1 height,o2 height) return integer is
begin
if o1.val > o2.val then return 1;
elsif o1.val < o2.val then return -1;
else return 0;
end if;
end;
end;
/
select p.height.val from people p order by height ASC;
| HEIGHT.VAL |
| ---------: |
| 130 |
| 150 |
| 180 |
select p.height.val from people p order by height DESC;
| HEIGHT.VAL |
| ---------: |
| 180 |
| 150 |
| 130 |
db<>fiddle here
In turned out to be a simple mistake...
Implementation of compare function compares self with self instead with other.

Insert Object data in Oracle 12c

I am trying to insert data in my table where one of the columns is of Object type, but I am getting the following error:
RA-06553: PLS-306: wrong number or types of arguments in call to 'SET_DATUME'
Table definition is:
CREATE TABLE Trebovanje (
BrDokumenta NUMBER,
Datumi DATUMI_T,
SifRJ NUMBER,
BrRadKnjiz NUMBER,
CONSTRAINT trebovanje_pk PRIMARY KEY (BrDokumenta),
CONSTRAINT treb_rj_fk FOREIGN KEY (SifRJ) REFERENCES RadnaJedinica (SifRJ),
CONSTRAINT trebovanje_zap_fk FOREIGN KEY (BrRadKnjiz) REFERENCES Zaposleni (BrRadKnjiz)
);
DATUMI_T user defined type:
create or replace TYPE DATUMI_T AS OBJECT (
DatPrijema DATE,
DatStampanja DATE,
MEMBER FUNCTION get_dat_prijema RETURN DATE,
MEMBER FUNCTION get_dat_stampanja RETURN DATE,
MEMBER PROCEDURE set_datume(p_dat_prijema DATE, p_dat_stampanja DATE),
MEMBER FUNCTION proveri_dat_stampanja(p_dat_stampanja DATE) RETURN BOOLEAN
);
create or replace TYPE BODY DATUMI_T AS
MEMBER FUNCTION get_dat_prijema RETURN DATE AS
BEGIN
RETURN self.DatPrijema;
END get_dat_prijema;
MEMBER FUNCTION get_dat_stampanja RETURN DATE AS
BEGIN
RETURN self.DatStampanja;
END get_dat_stampanja;
MEMBER PROCEDURE set_datume(p_dat_prijema DATE, p_dat_stampanja DATE) AS
BEGIN
self.DatPrijema := p_dat_prijema;
IF proveri_dat_stampanja(p_dat_stampanja)
THEN
self.DatStampanja := p_dat_stampanja;
ELSE
self.DatStampanja := SYSDATE;
END IF;
END set_datUME;
MEMBER FUNCTION proveri_dat_stampanja(p_dat_stampanja DATE) RETURN BOOLEAN AS
ok BOOLEAN;
BEGIN
ok := self.DatPrijema < p_dat_stampanja;
RETURN ok;
END proveri_dat_stampanja;
END;
And my insert statement:
insert into trebovanje values (
1,
DATUMI_T.set_datume(
TO_DATE('2017-01-02 17:44:33', 'YYYY-MM-DD HH24:MI:SS'),
TO_DATE('2017-01-02 17:55:33', 'YYYY-MM-DD HH24:MI:SS')
),
1,
1234);
Any thoughts on this?
What you seem to need is define a constructor that "hides" the default constructor.
CREATE OR REPLACE TYPE DATUMI_T AS OBJECT
(
DatPrijema DATE,
DatStampanja DATE,
MEMBER FUNCTION get_dat_prijema
RETURN DATE,
MEMBER FUNCTION get_dat_stampanja
RETURN DATE,
MEMBER PROCEDURE set_datume(p_dat_prijema DATE, p_dat_stampanja DATE),
MEMBER FUNCTION proveri_dat_stampanja(p_dat_stampanja DATE)
RETURN BOOLEAN,
/* the declaration of your own constructor ( same name of the type ) */
CONSTRUCTOR FUNCTION DATUMI_T(DatPrijema DATE, DatStampanja DATE)
RETURN SELF AS RESULT
);
create or replace TYPE BODY DATUMI_T AS
MEMBER FUNCTION get_dat_prijema RETURN DATE AS
BEGIN
RETURN self.DatPrijema;
END get_dat_prijema;
MEMBER FUNCTION get_dat_stampanja RETURN DATE AS
BEGIN
RETURN self.DatStampanja;
END get_dat_stampanja;
MEMBER PROCEDURE set_datume(p_dat_prijema DATE, p_dat_stampanja DATE) AS
BEGIN
self.DatPrijema := p_dat_prijema;
IF proveri_dat_stampanja(p_dat_stampanja)
THEN
self.DatStampanja := p_dat_stampanja;
ELSE
self.DatStampanja := SYSDATE;
END IF;
END set_datUME;
/* the body of your constructor */
CONSTRUCTOR FUNCTION DATUMI_T(DatPrijema DATE, DatStampanja DATE)
RETURN SELF AS RESULT as
BEGIN
self.DatPrijema := DatPrijema;
IF proveri_dat_stampanja(DatStampanja)
THEN
self.DatStampanja := DatStampanja;
ELSE
self.DatStampanja := SYSDATE;
END IF;
return;
END DATUMI_T;
MEMBER FUNCTION proveri_dat_stampanja(p_dat_stampanja DATE) RETURN BOOLEAN AS
ok BOOLEAN;
BEGIN
ok := self.DatPrijema < p_dat_stampanja;
RETURN ok;
END proveri_dat_stampanja;
END;

Query to find an average weighted price

I have a table in Oracle with multiple rows per a given part. Each row has a quantity and a price associated with it. There is also a total quantity that the set of rows for a given part adds up to. Below is a sample of the data. What I need is to get the average weighted price for the part. For example if a quantity of 100 of a part has a price of 1 and a quantity of 50 has a price of 2 the weighted average price is 1.33333333
PART TOTAL_QTY QTY PRICE_PER
----------------------------------
part1 317 244 27
part1 317 40 53.85
part1 317 33 24.15
Ideas?
Try this:
SELECT part, SUM(qty*price_per)/SUM(qty)
FROM <YOUR_TABLE>
GROUP BY part
create a user defined aggregate function to calculate the weighted average:
CREATE OR REPLACE TYPE WEIGHTED_AVG_O AS OBJECT (
sum_of_weights NUMBER,
sum_of_weights_times_value NUMBER,
STATIC FUNCTION ODCIAGGREGATEINITIALIZE(cs_ctx IN OUT WEIGHTED_AVG_O) RETURN NUMBER,
MEMBER FUNCTION ODCIAGGREGATEITERATE (self IN OUT WEIGHTED_AVG_O, value IN WEIGHTED_AVG_O) RETURN NUMBER,
MEMBER FUNCTION ODCIAGGREGATEMERGE (self IN OUT WEIGHTED_AVG_O, ctx2 IN OUT WEIGHTED_AVG_O) RETURN NUMBER,
MEMBER FUNCTION ODCIAGGREGATETERMINATE (self IN OUT WEIGHTED_AVG_O, returnvalue OUT NUMBER, flags IN NUMBER) RETURN NUMBER
);
/
CREATE OR REPLACE TYPE BODY WEIGHTED_AVG_O
AS
STATIC FUNCTION ODCIAGGREGATEINITIALIZE(cs_ctx IN OUT WEIGHTED_AVG_O) RETURN NUMBER
IS
BEGIN
cs_ctx := WEIGHTED_AVG_O(0, 0);
RETURN odciconst.success;
END;
MEMBER FUNCTION ODCIAGGREGATEITERATE (self IN OUT WEIGHTED_AVG_O, value IN WEIGHTED_AVG_O) RETURN NUMBER
IS
BEGIN
self.sum_of_weights := self.sum_of_weights + value.sum_of_weights;
self.sum_of_weights_times_value := self.sum_of_weights_times_value + value.sum_of_weights * value.sum_of_weights_times_value;
RETURN odciconst.success;
END;
MEMBER FUNCTION ODCIAGGREGATEMERGE (self IN OUT WEIGHTED_AVG_O, ctx2 IN OUT WEIGHTED_AVG_O) RETURN NUMBER
IS
BEGIN
RETURN odciconst.success;
END;
MEMBER FUNCTION ODCIAGGREGATETERMINATE (self IN OUT WEIGHTED_AVG_O, returnvalue OUT NUMBER, flags IN NUMBER) RETURN NUMBER
IS
BEGIN
IF sum_of_weights = 0 THEN
returnvalue := NULL;
ELSE
returnvalue := sum_of_weights_times_value / sum_of_weights;
END IF;
RETURN odciconst.success;
END;
END;
/
CREATE OR REPLACE FUNCTION WEIGHTED_AVG (input WEIGHTED_AVG_O)
RETURN NUMBER PARALLEL_ENABLE
AGGREGATE USING WEIGHTED_AVG_O;
/
query with your data:
SELECT part, WEIGHTED_AVG(WEIGHTED_AVG_O(qty, price_per))
FROM <YOUR_TABLE>
GROUP BY part;