次のようなトリガーを使用して、列を更新できます。
customer_id、recipe_number に一意の制約があるテーブル定義:
CREATE TABLE receipts (id serial primary key, customer_id bigint, receipt_number bigint default 1);
CREATE UNIQUE INDEX receipts_idx ON receipts(customer_id, receipt_number);
クライアントの最大領収書番号をチェックする関数、または以前の領収書がない場合は 1
CREATE OR REPLACE FUNCTION get_receipt_number() RETURNS TRIGGER AS $receipts$
BEGIN
-- This lock will block other transactions from doing anything to table until
-- committed. This may not offer the best performance, but is threadsafe.
LOCK TABLE receipts IN ACCESS EXCLUSIVE MODE;
NEW.receipt_number = (SELECT CASE WHEN max(receipt_number) IS NULL THEN 1 ELSE max(receipt_number) + 1 END FROM receipts WHERE customer_id = new.customer_id);
RETURN NEW;
END;
$receipts$ LANGUAGE 'plpgsql';
各行挿入で関数を起動するトリガー:
CREATE TRIGGER rcpt_trigger
BEFORE INSERT ON receipts
FOR EACH ROW
EXECUTE PROCEDURE get_receipt_number();
次に、以下を実行します。
db=> insert into receipts (customer_id) VALUES (1);
INSERT 0 1
db=> insert into receipts (customer_id) VALUES (1);
INSERT 0 1
db=> insert into receipts (customer_id) VALUES (2);
INSERT 0 1
db=> insert into receipts (customer_id) VALUES (2);
INSERT 0 1
db=> insert into receipts (customer_id) VALUES (2);
次の結果が得られます。
id | customer_id | receipt_number
----+-------------+----------------
14 | 1 | 1
15 | 1 | 2
16 | 2 | 1
17 | 2 | 2
18 | 2 | 3