Forum OpenACS Q&A: triggers and aggregates PG 7.1
Will it be possible for PG 7.1 to trigger with a "where-statement"?
For example :
create trigger general_links_rating_update
after insert or update on general_link_user_ratings where foo_x = foo_y
for each row
execute procedure trig_general_links_rating_update();
And what about the avg(int) aggregate.
With general_links for example it rounds the integers that are inside general_links_user_ratings and updates avg_rating of general_links with a rounded integer and not with a more detailed numeric...
Any suggestions how you can get more detail into that avg_rating? I wanted to insert 10 instead of 1 and 100 instead of 10 into general_link_user_ratings and then do a tcl-job on the output...
Is that clever?
create trigger general_links_rating_update
after insert or update on general_link_user_ratings where foo_x = foo_y
for each row
execute procedure trig_general_links_rating_update();
And what about the avg(int) aggregate.
With general_links for example it rounds the integers that are inside general_links_user_ratings and updates avg_rating of general_links with a rounded integer and not with a more detailed numeric...
Any suggestions how you can get more detail into that avg_rating? I wanted to insert 10 instead of 1 and 100 instead of 10 into general_link_user_ratings and then do a tcl-job on the output...
Is that clever?
Posted by
Carl Coryell-Martin
on 04/24/01 07:22 PM
Its probably much easier to put the where clause into the procedure:
IF foo_x = foo_y THEN do some some stuff; RETURN NULL; ELSE RETURN NULL; ENDIF;
As for the other problem, I think that you can cast the answer of the avg() to include more decimal places. Try looking up information about the numeric datatype. In the general-ratings module we wrote stored the average as a float. We also used a less expensive method of calculating the average (and std. devation!) by keeping track of some running totals. I'll enclose the code for fun:
create table cr_user_ratings ( user_id integer not null references users, axis_id integer not null references cr_rating_axes, on_what_id integer not null, on_which_table varchar(50, time_rated datetime not null, rating integer not null check (rating > 0 and rating <= 10), comment_id integer references general_comments, --id of associated general comment constraint unique_user_axis unique (user_id, axis_id, on_what_id) ); create table cr_compiled_ratings ( on_what_id integer not null, on_which_table varchar(50), axis_id integer not null references cr_rating_axes, average_rating float not null, last_compiled_on datetime not null, number_of_ratings integer not null, sum_ratings integer not null, sum_ratings_squared integer not null, std_dev_ratings float not null ); -- equation for Standard Deviation comes from HP 11C owners handbook -- and problem-solving guideThe idea was to not do a table scan one updates of a rating.create function cr_maintain_compiled_ratings() returns opaque as ' DECLARE -- the old compiled ratings information v_row cr_compiled_ratings%rowtype; BEGIN SELECT * into v_row FROM cr_compiled_ratings cr WHERE NEW.axis_id = cr.axis_id AND NEW.on_what_id = cr.on_what_id; IF FOUND THEN UPDATE cr_compiled_ratings SET average_rating = (v_row.sum_ratings+NEW.rating)::float / (v_row.number_of_ratings+1)::float, number_of_ratings = v_row.number_of_ratings + 1, sum_ratings = v_row.sum_ratings + NEW.rating, sum_ratings_squared = v_row.sum_ratings_squared + (NEW.rating^2), std_dev_ratings = sqrt( ( (v_row.number_of_ratings + 1) * (v_row.sum_ratings_squared + (NEW.rating^2) ) - ( (v_row.sum_ratings + NEW.rating)^2 ) ) / ( v_row.number_of_ratings * (v_row.number_of_ratings + 1) ) ), last_compiled_on = sysdate() WHERE axis_id = NEW.axis_id AND on_what_id = NEW.on_what_id; ELSE -- create new entry in ratings table INSERT INTO cr_compiled_ratings (on_what_id, on_which_table, axis_id, average_rating, last_compiled_on, number_of_ratings, sum_ratings, sum_ratings_squared, std_dev_ratings) VALUES (NEW.on_what_id, NEW.on_which_table, NEW.axis_id, NEW.rating, sysdate(), 1, NEW.rating, NEW.rating^2, 0); END IF; RETURN NULL; END;' language 'plpgsql'; create trigger cr_maintain_compiled_ratings_tr after insert on cr_user_ratings for each row execute procedure cr_maintain_compiled_ratings();
Cheers,