limit field's value with value from another table before write

与世无争的帅哥 提交于 2019-12-25 09:35:03

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!