@ Гленн дал вам очень элегантное решение с агрегатной функцией. Но чтобы ответить на ваш вопрос, функция plpgsql может выглядеть так:
Тестовая настройка:
CREATE TEMP TABLE mytable (
name text
, round int
, position int
, val double precision);
INSERT INTO mytable VALUES
('A', 1, 1, 0.5)
,('A', 1, 2, 3.4)
,('A', 1, 3, 2.2)
,('A', 1, 4, 3.8)
,('A', 2, 1, 0.5)
,('A', 2, 2, 32.3)
,('A', 2, 3, 2.21)
,('A', 2, 4, 0.8);
Общая функция
CREATE OR REPLACE FUNCTION f_grp_prod()
RETURNS TABLE (
name text
, round int
, result double precision) AS
$BODY$
DECLARE
r mytable%ROWTYPE;
BEGIN
-- init vars
name := 'A'; -- we happen to know initial value
round := 1; -- we happen to know initial value
result := 1;
FOR r IN
SELECT *
FROM mytable m
ORDER BY m.name, m.round
LOOP
IF (r.name, r.round) <> (name, round) THEN -- return result before round
RETURN NEXT;
name := r.name;
round := r.round;
result := 1;
END IF;
result := result * (1 - r.val/100);
END LOOP;
RETURN NEXT; -- return final result
END;
$BODY$ LANGUAGE plpgsql STABLE;
Звоните:
SELECT * FROM f_grp_prod();
Результат:
name | round | result
-----+-------+---------------
A | 1 | 0.90430333812
A | 2 | 0.653458283632
Специфическая функция согласно вопросу
CREATE OR REPLACE FUNCTION f_grp_prod(text)
RETURNS TABLE (
name text
, result1 double precision
, result2 double precision) AS
$BODY$
DECLARE
r mytable%ROWTYPE;
_round integer;
BEGIN
-- init vars
name := $1;
result2 := 1; -- abuse result2 as temp var for convenience
FOR r IN
SELECT *
FROM mytable m
WHERE m.name = name
ORDER BY m.round
LOOP
IF r.round <> _round THEN -- save result1 before 2nd round
result1 := result2;
result2 := 1;
END IF;
result2 := result2 * (1 - r.val/100);
_round := r.round;
END LOOP;
RETURN NEXT;
END;
$BODY$ LANGUAGE plpgsql STABLE;
Звоните:
SELECT * FROM f_grp_prod('A');
Результат:
name | result1 | result2
-----+---------------+---------------
A | 0.90430333812 | 0.653458283632