powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Rule: почему оно так работает?
19 сообщений из 19, страница 1 из 1
Rule: почему оно так работает?
    #36928187
Weed
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
есть таблица - лог платежей пользователей

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
CREATE TABLE "log".payments
(
  log_id integer NOT NULL DEFAULT nextval('log.log_id_seq'::regclass),
  "time" timestamp with time zone NOT NULL DEFAULT now(),
  deposit boolean NOT NULL,
  username text NOT NULL,
  currency_id text NOT NULL, -- разные валюты могут быть в платежах
  amount numeric NOT NULL, -- Не включает в себя сборы (fee_amount)
  fee_amount numeric NOT NULL DEFAULT  0 ,
  merchant_fee_amount numeric NOT NULL DEFAULT  0 ,
  merchant text,
  CONSTRAINT deposits_withdraws_pkey PRIMARY KEY (log_id),
  CONSTRAINT deposits_withdraws_username_fkey FOREIGN KEY (username)
      REFERENCES users.users (username) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE SET NULL
);

у неё есть правило, которое отнимает и прибавляет деньги на лицевом счету пользователей:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
CREATE OR REPLACE RULE "50_credit_debit" AS
    ON INSERT TO log.payments DO  UPDATE users.funds f SET amount = f.amount + 
        CASE
            WHEN new.deposit THEN new.amount
            ELSE - (new.amount + new.fee_amount)
        END
  WHERE f.username = new.username AND f.currency_id = new.currency_id;
COMMENT ON RULE "50_credit_debit" ON "log".payments IS 'Начисление/списание средств пользователей';

лицевые счета хранятся тут:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
CREATE TABLE users.funds
(
  fund_id serial NOT NULL,
  username text NOT NULL,
  currency_id text NOT NULL,
  amount numeric NOT NULL DEFAULT  0 ,
  CONSTRAINT funds_pkey PRIMARY KEY (fund_id),
  CONSTRAINT funds_currency_fkey FOREIGN KEY (currency_id)
      REFERENCES rates.currencies (currency_id) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE CASCADE,
  CONSTRAINT funds_username_fkey FOREIGN KEY (username)
      REFERENCES users.users (username) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE CASCADE,
  CONSTRAINT funds_username_key UNIQUE (username, currency_id),
  CONSTRAINT "100_amount_not_less_than_0" CHECK (NOT amount <  0 ::numeric)
);

казалось бы, всё отлично работает. Но, если сделать запись в лог сразу двух строк таким образом:

Код: plaintext
1.
2.
3.
4.
5.
insert into "log".payments
(deposit, username, currency_id, amount)
values
(true, 'Вася', 'MMM',  150 ), -- 'МММ' это название тестовой валюты
(true, 'Вася', 'MMM',  50 )

то на счету пользователя прибавляется только 150 единиц денег а не 200

Вопрос: почему так происходит?
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36928267
Фотография Ёш
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Weed, а версия сервера у Вас какая?
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36928323
Big Andy
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
После автор(true, 'Вася', 'MMM', 50) поставить точку с запятой?
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36928340
Weed
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЁшWeed, а версия сервера у Вас какая?

/usr/lib/postgresql/9.0/bin/postgres --version
postgres (PostgreSQL) 9.0.1

дебиановский пакет:
postgresql-9.0 9.0.1-1

Big AndyПосле автор(true, 'Вася', 'MMM', 50) поставить точку с запятой?

нее, это я просто из pgadmin3 запрос делал, дело не в этом
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36928363
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Weed,

255 раз писали не используйте рулы для чего то сложнее перевода insert/delete/update из views.

А ответ почему так содержится в том механизме как рулы работают... например вот тут вот:
http://www.depesz.com/index.php/2010/06/15/to-rule-or-not-to-rule-that-is-the-question/
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36928382
Weed
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim BogukWeed,

255 раз писали не используйте рулы для чего то сложнее перевода insert/delete/update из views.

А ответ почему так содержится в том механизме как рулы работают... например вот тут вот:
http://www.depesz.com/index.php/2010/06/15/to-rule-or-not-to-rule-that-is-the-question/

у правил есть один плюс, который для меня лично перекрывает всё:

по сравнению с триггерми в них практически не бывает синтаксических ошибок, что позволяет отловить проблему в момент сохранения правила а не в момент когда юзеры начнут жаловаться

это же касается и изменений в БД - триггер не поднимет тревогу если нужное ему поле таблицы внезапно пропало
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36928561
Weed
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я правильно написал, парсер именно так распарсит правило?

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE OR REPLACE RULE "50_credit_debit" AS
    ON INSERT TO log.payments DO  

UPDATE users.funds f SET amount = f.amount + 
        CASE
            WHEN new.deposit THEN new.amount
            ELSE - (new.amount + new.fee_amount)
        END

FROM payments new -- только новые строки!
WHERE f.username = new.username AND f.currency_id = new.currency_id;

в упор не вижу что тут криминального?
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36928593
Weed
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Weed,

а, всё понял, несколько раз set amount = amount + n вызывается для одной и той же строки

никогда не думал что подряд выставленные значения set для одной строки не сохраняются а перезаписываются

дело тут даже и не в рулесах
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36928595
Фотография Ёш
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Weed, судя по всему у парсера после вставки правила в запрос получается что-то типа такого:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
create table t (i int, v int);
insert into t values ( 1 ,  10 );
update t set v = v +  10  where i in ( 1 ,  1 );
select * from t;
 i | v
---+----
  1  |  20 
( 1  запись)
несмотря на то что в where указано два значения, оба значения равны и update выполняется по сути один раз.

ps: Вообще, согласитесь, было бы странно если бы UPDATE выполнялся для одной и той же строки несколько раз в одном запросе
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36928633
Фотография Ёш
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WeedЯ правильно написал, парсер именно так распарсит правило?

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE OR REPLACE RULE "50_credit_debit" AS
    ON INSERT TO log.payments DO  

UPDATE users.funds f SET amount = f.amount + 
        CASE
            WHEN new.deposit THEN new.amount
            ELSE - (new.amount + new.fee_amount)
        END

FROM payments new -- только новые строки!
WHERE f.username = new.username AND f.currency_id = new.currency_id;

в упор не вижу что тут криминального?Не в FROM, а в WHERE, как Вы сами написали. На FROM сервер ругается:
Код: plaintext
1.
2.
3.
4.
5.
create rule foo as on insert to t do also
update u set v = v + show_v(i, new.v)
from (select new.i) as x
where (i = new.i) and (show_ctid(ctid) is not null);
ERROR:  subquery in FROM cannot refer to other relations of same query level
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36928681
Анонимус
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Weed,

авторcurrency_id text NOT NULL
сильно.
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36929011
Weed
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
анонимусWeed,

авторcurrency_id text NOT NULL
сильно.

что не так?
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36929014
Weed
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ёш,

получается, на рулесах в принципе нельзя такой запрос как мне надо написать?

аггрегат sum() оно не позволяет на псевдореляцию new натравить...
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36933290
1chainik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Weed у правил есть один плюс, который для меня лично перекрывает всё:

по сравнению с триггерми в них практически не бывает синтаксических ошибок, что позволяет отловить проблему в момент сохранения правила а не в момент когда юзеры начнут жаловаться

это же касается и изменений в БД - триггер не поднимет тревогу если нужное ему поле таблицы внезапно пропало

а ,старый знакомый :
авторя избегаю повторяющихся почти одинаковых запросов. если бы я расписал на 2 запроса это то лучше бы точно не стало, визуально легко было бы потерять где в какую сторону условие или сортировка.

я уже даже один раз так потерял - пришлось по логам базу восстанавливать (ценный опыт :))

а чтобы возвращаться обильно поливаю каментами каждое действие"а он всегда был спорщиком - припрут к стене - откажется. прошёл он коридорчиком и кончил стенкой, кажется"


PS мне очень интересно, как триггер не пошлёт вас лесом, если поле ,им пользуемое, пропадёт. наверное вы поленитесь проверить срабатывание триггеров после альтер-таблицы. я правильно понял?


(и очень интересно, зачем дропать поля в таблице. особо если учесть, что реально они в постгресе не дропаются).
а "внезапно"(тм) так вообще - пестня.
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36933338
1chainik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WeedWeed,

а, всё понял, несколько раз set amount = amount + n вызывается для одной и той же строки

никогда не думал что подряд выставленные значения set для одной строки не сохраняются а перезаписываются

дело тут даже и не в рулесах именно в рулесах.
рулесы это не триггера, а "макросы". все значения в строках рулесов "макровычислимы", а не "последовательно обновимы", как вам тут требуется. (забавно, что вы еще не знаете что в многострочном рулесе сам состав (и количество строк) NEW может поменяться, т.к. рулесы еще и "атомарности" не обеспечивают. NEW это даже не "снепшот")

рулесы в постгресе это макробаг. а любители рулесов (упорствующие) - сами себе буратинки. (я тоже как-то убил кучу времени на).
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36933354
1chainik
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вот придумал
- попробуйте такую шнягу:
распишите в многострочный руле с криэйт-темп-табл примерно как AS SELECT NEW.* и вставкой агрегата уже из темпа. может и получиться. если рулес не потеряет темп-таблу между своими стейтментами. (можно и через постоянку робить, но с идентификатором транзакции [или чего-то подобного] в ключе. как выцеплять ид транзакции кажется тут встречалось).
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36937086
Weed
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
1chainikвот придумал
- попробуйте такую шнягу:
распишите в многострочный руле с криэйт-темп-табл примерно как AS SELECT NEW.* и вставкой агрегата уже из темпа. может и получиться. если рулес не потеряет темп-таблу между своими стейтментами. (можно и через постоянку робить, но с идентификатором транзакции [или чего-то подобного] в ключе. как выцеплять ид транзакции кажется тут встречалось).

спасибо, это уже как то чересчур. сделал таки триггером.

про триггеры и рулесы:
когда в базе среднего размера (50 таблиц) всего два триггера уследить за ними не сложно
...
Рейтинг: 0 / 0
Rule: почему оно так работает?
    #36952682
Hacker-CB
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
У меня один-в один ситуация, тоже баланс лицевого счета нужно обновлять.
После того как с этим столкнулся, полностью ушел от рулесов, оставил их только для view.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
Rule: почему оно так работает?
    #39474523
eddie
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
тоже столкнулся с такой проблемой, подумал, как исправить и минимальными передалками - сделал функцию adjust_balance(id, delta), которая изменяет баланс на нужную сумму, и зову её из rule.
по сути получились самодельные триггеры


1chainik(забавно, что вы еще не знаете что в многострочном рулесе сам состав (и количество строк) NEW может поменяться, т.к. рулесы еще и "атомарности" не обеспечивают. NEW это даже не "снепшот") вот это предложение хотелось бы расшифровать
...
Рейтинг: 0 / 0
19 сообщений из 19, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Rule: почему оно так работает?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]