问题
Are Postgres TRIGGERs transactional by default like (I've read) in MySQL?
I've created a TRIGGER procedure that uses a simple IF to limit a column's value with a value from another TABLE with a subsequent UPDATE if the limit is breached.
I'd prefer that to be in one single TRANSACTION, but if I wrap the IF...THEN UPDATE with BEGIN...COMMIT, it gives error
SQL error:
ERROR: syntax error at or near ";"
LINE 2: BEGIN;
^
Are TRIGGERs TRANSACTIONal by default? If not, how can a TRIGGER be made TRANSACTIONal?
code
This is ON INSERT OR UPDATE of articles:
BEGIN
BEGIN; /* this first TRANSACTION line causes error */
IF (NEW.votes_used > (SELECT votes_available FROM vote_totals
WHERE vote_totals.user_id = NEW.user_id)) THEN
UPDATE articles SET votes_used = (SELECT votes_available FROM vote_totals
WHERE vote_totals.userID = NEW.user_id) WHERE user_id = NEW.user_id;
END IF;
COMMIT; /*last TRANSACTION line */
RETURN NULL;
END;
I'd MUCH rather do a CHECK or FOREIGN to nip this in the bud before the data even gets in, but I don't know how to do it with a FOREIGN, and I've read that CHECKs can't use subqueries. I think I read that this is the way to go, but I must disclose that I'm db noob.
回答1:
You do not need UPDATE inside a trigger. You can assign the value to NEW.votes_used
Use something like:
BEGIN
IF (NEW.votes_used > (SELECT votes_available FROM vote_totals
WHERE vote_totals.user_id = NEW.user_id)) THEN
NEW.votes_used := (SELECT votes_available FROM vote_totals
WHERE vote_totals.userID = NEW.user_id);
END IF;
RETURN NEW;
END;
Or
BEGIN
NEW.votes_used := LEAST(NEW.votes_used, (SELECT votes_available
FROM vote_totals
WHERE vote_totals.userID = NEW.user_id));
RETURN NEW;
END;
This must be a BEFORE UPDATE trigger to work. (And as all BEFORE UPDATE triggers it must RETURN NEW).
If you want to emulate check constraint with trigger - try something like:
BEGIN
IF (NEW.votes_used > (SELECT votes_available
FROM vote_totals
WHERE vote_totals.user_id = NEW.user_id))
THEN RAISE EXCEPTION 'Not enough votes';
END IF;
RETURN NEW;
END;
回答2:
Triggers are transactional in the sense that their actions can be rolled back. You don't have to do anything to make them work like that.
The syntax error is just that. It's hard to tell you more without seeing the code.
来源:https://stackoverflow.com/questions/19251236/limit-fields-value-with-value-from-another-table-before-write