У меня есть таблица:
-- TABLE --
DROP SEQUENCE IF EXISTS my_db.tbl_a_id_seq CASCADE;
DROP TABLE IF EXISTS my_db.tbl_a CASCADE;
CREATE SEQUENCE my_db.tbl_a_id_seq;
CREATE TABLE my_db.tbl_a
(
id integer NOT NULL DEFAULT nextval('my_db.tbl_a_id_seq'::regclass),
bill_date timestamp without time zone,
bill_amt numeric(10,2),
charge_id integer,
sp_id integer,
batch_id integer,
bal_before numeric(10,2),
bal_after numeric(10,2),
CONSTRAINT tbl_a_pkey PRIMARY KEY (id)
)
WITH (
OIDS = FALSE
);
DROP INDEX IF EXISTS idx_tbl_a_my_cols CASCADE;
CREATE INDEX idx_tbl_a_my_cols
ON my_db.tbl_a USING btree
(bill_date ASC NULLS LAST, bal_before ASC NULLS LAST);
Затем я заполняю вышеприведенную таблицу двумя начальными данными строк, поэтому таблица теперь выглядит следующим образом:
id | bill_date | bill_amt | charge_id | sp_id | batch_id | bal_before | bal_after
----+----------------------------+----------+-----------+-------+----------+------------+-----------
1 | 2020-04-13 11:21:26.51637 | 10.00 | 1 | 1 | 2 | 200.00 | 190.00
2 | 2020-04-13 11:23:37.317907 | 10.00 | 1 | 1 | 2 | 190.00 | 180.00
Затем я создал триггер функция и ее триггер, который должен вставлять значения bal_before в только что вставленную строку из значения bal_after самой предыдущей строки. После этого заполняют только что вставленный столбец bal_after строки значением, вычисленным путем вычитания значения столбца bill_amt вставленной строки jusst из значения bal_before той же строки (это значение bal_before, которое было вычислено из оконной функции LAG
Postgresql). Указанные функция и триггер следующие:
-- TRIGGER FUNCTION --
SET search_path TO 'my_db';
CREATE OR REPLACE FUNCTION func_calc_balances() RETURNS TRIGGER AS
$$
BEGIN
NEW.bal_before:=
(
WITH filter_table as (
SELECT id, bill_amt, bal_after
FROM my_db.tbl_a
WHERE charge_id = 1
AND sp_id = 1
AND batch_id = 2
ORDER BY id DESC LIMIT 2
)
SELECT
lag(bal_after, 1) over (order by id)
FROM filter_table
ORDER BY id DESC LIMIT 1
);
NEW.bal_after := (NEW.bal_before - NEW.bill_amt);
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
-- ABOVE FUNCTION'S TRIGGER --
DROP TRIGGER IF EXISTS trigger_calc_balances ON my_db.tbl_a CASCADE;
CREATE TRIGGER trigger_calc_balances
BEFORE INSERT OR UPDATE ON "tbl_a" FOR EACH ROW EXECUTE PROCEDURE func_calc_balances();
При вставке строк в таблицу процедура триггера действует странно; время от времени он заполняется должным образом, иногда он повторяет значения столбца, что означает, что он не извлекает самую ближайшую предыдущую строку, чтобы использовать ее для заполнения следующей прямой строки. Пример странного вывода приведен ниже:
Странное поведение в Ubuntu и Windows, если я использую функцию generate_series для заполнения (чередующиеся строки имеют нулевые значения bal_before и bal_after)
id | bill_date | bill_amt | charge_id | sp_id | batch_id | bal_before | bal_after
----+----------------------------+----------+-----------+-------+----------+------------+-----------
1 | 2020-04-13 11:21:26.51637 | 10.00 | 1 | 1 | 2 | 200.00 | 190.00
2 | 2020-04-13 11:23:37.317907 | 10.00 | 1 | 1 | 2 | |
3 | 2020-04-13 11:52:11.326197 | 10.00 | 1 | 1 | 2 | 190.00 | 180.00
4 | 2020-04-13 11:52:13.629896 | 10.00 | 1 | 1 | 2 | |
5 | 2020-04-13 11:52:14.977964 | 10.00 | 1 | 1 | 2 | 180.00 | 170.00
6 | 2020-04-13 11:52:16.062277 | 10.00 | 1 | 1 | 2 | |
Странное поведение при Windows, если я заполняю немного медленно (значения не обновляются в некотором bal_before)
id | bill_date | bill_amt | charge_id | sp_id | batch_id | bal_before | bal_after
----+----------------------------+----------+-----------+-------+-----------+------------+-----------
1 | 2020-04-13 11:28:09.667957 | 10.00 | 1 | 1 | 2 | 200.00 | 190.00
2 | 2020-04-13 11:29:09.667957 | 10.00 | 1 | 1 | 2 | 190.00 | 180.00
3 | 2020-04-13 11:30:09.667957 | 10.00 | 1 | 1 | 2 | 180.00 | 170.00
4 | 2020-04-13 11:42:32.655569 | 10.00 | 1 | 1 | 2 | 180.00 | 170.00
5 | 2020-04-13 11:42:43.739626 | 10.00 | 1 | 1 | 2 | 170.00 | 160.00
6 | 2020-04-13 11:42:44.788808 | 10.00 | 1 | 1 | 2 | 170.00 | 160.00
Желаемый результат как следует:
id | bill_date | bill_amt | charge_id | sp_id | batch_id | bal_before | bal_after
----+----------------------------+----------+-----------+-------+-----------+------------+-----------
1 | 2020-04-13 11:29:09.667957 | 10.00 | 1 | 1 | 2 | 200.00 | 190.00
2 | 2020-04-13 11:29:09.667957 | 10.00 | 1 | 1 | 2 | 190.00 | 180.00
3 | 2020-04-13 11:30:09.667957 | 10.00 | 1 | 1 | 2 | 180.00 | 170.00
4 | 2020-04-13 11:28:09.667957 | 10.00 | 1 | 1 | 2 | 170.00 | 160.00
5 | 2020-04-13 11:42:32.655569 | 10.00 | 1 | 1 | 2 | 160.00 | 150.00
6 | 2020-04-13 11:42:43.739626 | 10.00 | 1 | 1 | 2 | 150.00 | 140.00
7 | 2020-04-13 11:42:44.788808 | 10.00 | 1 | 1 | 2 | 140.00 | 130.00
Я считаю, что должна быть проблема в моей функции триггера. Когда функция пропускает некоторые строки (оставляя нулевые значения в нужных столбцах), обновление работает должным образом последовательно, только если оно пропускает некоторые строки. Пожалуйста помогите.