问题
))Hi all, this is my table...

Currently Im using this function trigger...
IF NEW.timetype = 'Total' THEN
SELECT SUM(timeelapse) FROM (SELECT DISTINCT ON (floor(timeindex)::int) floor(timeindex)::int timeindex, timeelapse FROM mytable WHERE pcnum = NEW.pcnum AND fnname = NEW.fnname AND timetype = 'Lap' ORDER BY 1, 2 DESC) alias INTO v_sumtimeelapse_fn;
IF FOUND THEN
NEW.timeelapse := v_sumtimeelapse_fn;
ELSE
RAISE EXCEPTION USING MESSAGE = 'There is not any previous row...';
END IF;
END IF;
So whenever 'Total' is INSERTed on the timetype column it SUMs up all timeelapse FROM mytable WHERE pcnum = NEW.pcnum AND fnname = NEW.fname AND timetype = 'Lap' but only where timeindex has the highest centesimal value (in mytable they would be the first three skyblue highighted squares = 00:01:00, 00:03:00, 00:04:00 (1.001, 2.003, 3.003)) and place the result in the NEW.timeelapse (in mytable it would be the first blue highlighted square = 00:08:00)
The function makes the SUM correctly, but I would like to add two more rules to it...
when 'Total' is INSERTed in timetype, if the function doesn't find any 'Lap' after a 'Start' (both with the same pcnum and fnname) then it should show an ERROR MESSAGE "'there isn't any Lap..." (in mytable it would be the red highlighted square). Note that there isn't any 'Lap' of fnname = 'bbbb' after 'Start' of fnname = 'bbbb'. I try to set my function to do so, using...
RAISE EXCEPTION USING MESSAGE = 'There is not any previous row...'
but it just doesn't work, if I INSERT a 'Total' in that situation, it simple leaves the NEW.timeelapse NULL.
- The function should SUM the timeelapse with all its already set rules, but only FROM those which are below the last(descendent) 'Total' of the same pcnum and fnname (in mytable it will be the second blue highlighted square) Note that it SUM only the timeelapses that are after the last(descendet) 'Total' (in mytable it will be the fourth skyblue highlighted square).
Thanks Advanced.
回答1:
To exclude from the calculation rows earlier than last Total
you can use the primary key in an accessory query.
Declare new variable v_fnserial
.
Find a fnserial
of the row with last occurence of 'Total' for given pcnum
and fnname
and assign the value to v_fnserial
.
In the main query add a condition fnserial > v_fnserial
.
You should raise an exception when the main query returns null
.
IF NEW.timetype = 'Total' THEN
SELECT fnserial INTO v_fnserial
FROM mytable
WHERE timetype = 'Total' AND pcnum = NEW.pcnum AND fnname = NEW.fnname
ORDER BY fnserial DESC LIMIT 1;
SELECT SUM(timeelapse) FROM (
SELECT DISTINCT ON (floor(timeindex)::int) floor(timeindex)::int timeindex, timeelapse
FROM mytable
WHERE fnserial > coalesce(v_fnserial, 0) AND pcnum = NEW.pcnum AND fnname = NEW.fnname AND timetype = 'Lap'
ORDER BY 1, 2 DESC) alias
INTO v_sumtimeelapse_fn;
IF v_sumtimeelapse_fn NOTNULL THEN
NEW.timeelapse := v_sumtimeelapse_fn;
ELSE
RAISE EXCEPTION USING MESSAGE = 'There is not any previous row...';
END IF;
END IF;
来源:https://stackoverflow.com/questions/31145580/how-to-sum-up-all-rows-based-on-a-enumeration-column-in-postgresql-part2