Glue between TABLE and CURSOR functions in SQL?
714351Jul 28 2009 — edited Jul 29 2009I want to write a table function that takes a cursor as input and returns statistic computations as tabular data. The cursor is somewhat similiar to an inner select that is ecapsulated in an outer query performing the required statictical computations. The intention is to provide a standardized interface to a fixed set of statistic computations that can be used for different series of input values described by means of sql queries, e.g.
WITH measurements
AS (SELECT station, ts, val
FROM (SELECT 1 station, SYSDATE ts, 1.3 val FROM DUAL
UNION ALL
SELECT 1 station, SYSDATE - 1 ts, 1.1 val FROM DUAL
UNION ALL
SELECT 1 station, SYSDATE - 2 ts, 1.2 val FROM DUAL
UNION ALL
SELECT 1 station, SYSDATE - 3 ts, 1.5 val FROM DUAL
UNION ALL
SELECT 1 station, SYSDATE - 4 ts, 1.1 val FROM DUAL
UNION ALL
SELECT 2 station, SYSDATE ts, 1.35 val FROM DUAL
UNION ALL
SELECT 2 station, SYSDATE - 1 ts, 1.2 val FROM DUAL
UNION ALL
SELECT 2 station, SYSDATE - 2 ts, 1.12 val FROM DUAL
UNION ALL
SELECT 2 station, SYSDATE - 3 ts, 1.11 val FROM DUAL
UNION ALL
SELECT 2 station, SYSDATE - 4 ts, 1.01 val FROM DUAL))
SELECT station,
MIN (val) MIN,
MAX (val) MAX,
AVG (val) AVG
FROM measurements
GROUP BY station;
should be computable as follows
SELECT *
FROM TABLE(aggfunc(CURSOR(SELECT station, ts, val
FROM (SELECT 1 station,
SYSDATE ts,
1.3 val
FROM DUAL
UNION ALL
SELECT 1 station,
SYSDATE - 1 ts,
1.1 val
FROM DUAL
UNION ALL
SELECT 1 station,
SYSDATE - 2 ts,
1.2 val
FROM DUAL
UNION ALL
SELECT 1 station,
SYSDATE - 3 ts,
1.5 val
FROM DUAL
UNION ALL
SELECT 1 station,
SYSDATE - 4 ts,
1.1 val
FROM DUAL
UNION ALL
SELECT 2 station,
SYSDATE ts,
1.35 val
FROM DUAL
UNION ALL
SELECT 2 station,
SYSDATE - 1 ts,
1.2 val
FROM DUAL
UNION ALL
SELECT 2 station,
SYSDATE - 2 ts,
1.12 val
FROM DUAL
UNION ALL
SELECT 2 station,
SYSDATE - 3 ts,
1.11 val
FROM DUAL
UNION ALL
SELECT 2 station,
SYSDATE - 4 ts,
1.01 val
FROM DUAL))));
My blueprint implementation so far looks as follows. However, rather using the input cursor the analysis is backed by a harcoded inner query.
The comment marks where the cursor should be used.
Anyone any ideas?
CREATE OR REPLACE TYPE STATISTIC_OT
IS
OBJECT (STATION NUMBER (4), MIN NUMBER, MAX NUMBER, AVG NUMBER);
CREATE OR REPLACE TYPE STATISTICS_T IS TABLE OF STATISTIC_OT;
CREATE OR REPLACE FUNCTION aggfunc (measurements_in SYS_REFCURSOR)
RETURN STATISTICS_T
PIPELINED
IS
CURSOR stats
IS
WITH measurements
AS (SELECT station, ts, val
FROM (SELECT 1 station, SYSDATE ts, 1.3 val FROM DUAL
UNION ALL
SELECT 1 station, SYSDATE - 1 ts, 1.1 val
FROM DUAL
UNION ALL
SELECT 1 station, SYSDATE - 2 ts, 1.2 val
FROM DUAL
UNION ALL
SELECT 1 station, SYSDATE - 3 ts, 1.5 val
FROM DUAL
UNION ALL
SELECT 1 station, SYSDATE - 4 ts, 1.1 val
FROM DUAL
UNION ALL
SELECT 2 station, SYSDATE ts, 1.35 val FROM DUAL
UNION ALL
SELECT 2 station, SYSDATE - 1 ts, 1.2 val
FROM DUAL
UNION ALL
SELECT 2 station, SYSDATE - 2 ts, 1.12 val
FROM DUAL
UNION ALL
SELECT 2 station, SYSDATE - 3 ts, 1.11 val
FROM DUAL
UNION ALL
SELECT 2 station, SYSDATE - 4 ts, 1.01 val
FROM DUAL))
SELECT station,
MIN (val) MIN,
MAX (val) MAX,
AVG (val) AVG
FROM measurements /* <======= rather reference/use input parameter measurements_in */
GROUP BY station;
l_statistic STATISTIC_OT
:= STATISTIC_OT (NULL,
NULL,
NULL,
NULL) ;
l_station NUMBER (4);
l_min NUMBER;
l_max NUMBER;
l_avg NUMBER;
BEGIN
OPEN stats;
LOOP
FETCH stats INTO l_station, l_min, l_max, l_avg;
EXIT WHEN stats%NOTFOUND;
l_statistic.station := l_station;
l_statistic.MIN := l_min;
l_statistic.MAX := l_max;
l_statistic.AVG := l_avg;
PIPE ROW (l_statistic);
END LOOP;
CLOSE stats;
RETURN;
END aggfunc;
/