问题
Are Postgres TRIGGER
s 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 TRIGGER
s TRANSACTION
al by default? If not, how can a TRIGGER
be made TRANSACTION
al?
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 CHECK
s 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