powered by simpleCommunicator - 2.0.52     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / INSRT ... VALUES (DEFAULT)
12 сообщений из 12, страница 1 из 1
INSRT ... VALUES (DEFAULT)
    #35570428
Jelis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день!
Нужно при инсерте вставлять либо переданное значение, либо если оно NULL, до DEFAULT значение. Так как этот инсерт происходит в RULE на вьюху, просто опустить поле не получиться. Т.е. сейчас я делаю так:
Код: plaintext
1.
2.
3.
4.
5.
INSERT INTO Table1(f1) 
                   VALUES( COALESCE(NEW.f1, 'наше дефалтное значение') ) ; 
                   -- COALESCE(NEW.f1, DEFAULT) не проходит
                   -- поскольку видть это уже вызов функции
                   -- пишет  syntax error at or near "DEFAULT"

Если поступать таким образом, то приходиться дублировать дефалтные значения и в описании таблицы, и во всех рулях где оно должно вставляться. А это усложняем дальнейшую поддержку и хочеться как нибудь от этого избавиться. Возможно ли?
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
INSRT ... VALUES (DEFAULT)
    #40009032
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Прошло 12 лет. Проблема по-прежнему не решена...
Или это никому не нужно ?
...
Рейтинг: 0 / 0
INSRT ... VALUES (DEFAULT)
    #40009034
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cyrax_02
Прошло 12 лет. Проблема по-прежнему не решена...
Или это никому не нужно ?


Никому не нужно... rule - deprecated де факто фича.
Тем более что задача insert в view решается сейчас через instead of триггера которые нормально и предсказуемо (и понятно) работают в отличии от rule.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
INSRT ... VALUES (DEFAULT)
    #40009041
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk Никому не нужно... rule - deprecated де факто фича. Правила перезаписи запросов работают быстрее, чем триггеры , т.к. оптимизации подвергается результат развёртывания этих самых правил .

Ещё и это:
https://stackoverflow.com/questions/42520134/infinite-recursion-in-postgresql-rule#comment72194762_42520134 With high concurrency, a trigger based solution could fail...
...
Рейтинг: 0 / 0
INSRT ... VALUES (DEFAULT)
    #40009048
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk Тем более что задача insert в view решается сейчас через instead of триггера которые нормально и предсказуемо (и понятно) работают в отличии от rule
Тогда интересно, как решается сабжевая задача на уровне триггеров (вставка переданного значения, а если не передано, то DEFAULT) ?
...
Рейтинг: 0 / 0
INSRT ... VALUES (DEFAULT)
    #40009054
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cyrax_02
Maxim Boguk Тем более что задача insert в view решается сейчас через instead of триггера которые нормально и предсказуемо (и понятно) работают в отличии от rule

Тогда интересно, как решается сабжевая задача на уровне триггеров (вставка переданного значения, а если не передано, то DEFAULT) ?

дайте полное описание задачи чтоли...

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
INSRT ... VALUES (DEFAULT)
    #40009061
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Bogukдайте полное описание задачи чтоли...
Например, при вставке/обновлении записи в представлении для одного из полей нужно заменить значение NEW.fieldx на func(NEW.fieldx) .
При этом все остальные поля сохраняются без изменений. Т.е. если некоторое поле не указано, должно сохраняться значение DEFAULT (при наличии), а не NULL.
...
Рейтинг: 0 / 0
INSRT ... VALUES (DEFAULT)
    #40009066
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cyrax_02
Maxim Bogukдайте полное описание задачи чтоли...

Например, при вставке/обновлении записи в представлении для одного из полей нужно заменить значение NEW.fieldx на func(NEW.fieldx) .
При этом все остальные поля сохраняются без изменений. Т.е. если некоторое поле не указано, должно сохраняться значение DEFAULT (при наличии), а не NULL.

Да легко:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
create table test (id integer not null, ctime timestamp not null default now());

create view v_test as select id, ctime from test;

create or replace function f_trg_insert_test() returns trigger as $$
declare
begin
  NEW.id := NEW.id+1;
  insert into test (id, ctime) select NEW.*;
  return NEW;
end;
$$ language plpgsql;

create trigger insert_test_trg
instead of insert on v_test
for each row execute function f_trg_insert_test();



далее - ожидаемо имеем проблему:
Код: plaintext
1.
2.
3.
4.
5.
insert into v_test (id) values (10);
ERROR:  null value in column "ctime" violates not-null constraint
DETAIL:  Failing row contains (11, null).
CONTEXT:  SQL statement "insert into test (id, ctime) select NEW.*"
PL/pgSQL function f_trg_insert_test() line 5 at SQL statement

а теперь фокус - прописываем default value в view явным образом:
alter table v_test alter ctime set default now();
и все магически начинает работать

Код: plaintext
1.
2.
3.
4.
5.
6.
insert into v_test (id) values (10);
INSERT 0 1
select * from test;
 id |           ctime            
----+----------------------------
 11 | 2020-10-15 22:16:37.034059


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
INSRT ... VALUES (DEFAULT)
    #40009074
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Bogukдалее - ожидаемо имеем проблему:
insert into v_test (id) values (10);
ERROR: null value in column "ctime" violates not-null constraint
Неа. Так не пойдёт. Это ненормально. Внутри триггерной функции вставка выполняется не в представление, а в таблицу. Стало быть, на уровне этой вставки табличный DEFAULT должен использоваться по умолчанию. Возможны 2 реализации:
1 ) Если среди вставляемых полей некоторое поле отсутствует, внутри триггерной функции NEW.ctime должно иметь значение не NULL, а табличный DEFAULT для этого поля
2 ) NEW.ctime должно принимать некоторое специальное значение, отличное от NULL, соответствующее отсутствию значения во входных данных

Судя по всему, в PostgreSQL не реализован ни один из этих вариантов. В итоге мы имеем нерешённую проблему, когда при вставке в таблицу отсутствующего значения NEW.ctime = NULL, при этом невозможно определить, вставляется значение NULL или значение отсутствует (данное поле не сохраняется). А это разные ситуации.

В случае с правилом RULE INSTEAD OF такое поведение (бездействие) оправданно, поскольку правило применяется до выполнения запроса, а для каждой вставляемой записи значения будут разными. Но данное поведение ничем не оправданно в случае с триггерами, когда все сохраняемые значения на момент выполнения триггерной функции известны.

Maxim Bogukа теперь фокус - прописываем default value в view явным образом:
alter table v_test alter ctime set default now();
и все магически начинает работать
В данном случае проблема не решается, а всего лишь обходится. Тем, что мы не допускаем ситуации, когда в поле ctime таблицы вставляется значение NULL: при вставке в представление отсутствующее поле ctime принимает значение DEFAULT = now() (ещё до вызова триггера) и в момент срабатывания триггера NEW.ctime равно now() , а не NULL. Тем самым, проблему мы обходим, но не решаем.
...
Рейтинг: 0 / 0
INSRT ... VALUES (DEFAULT)
    #40009077
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вариант с триггерами (на каждой вставляемой строке вызывается триггерная функция, и даже не SQL , а более тяжёлая pgplSQL ):
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
create or replace function f_trg_insert_test() returns trigger as $$
declare
begin
  NEW.id := NEW.id+1;
  insert into test (id, ctime) select NEW.*;
  return NEW;
end;
$$ language plpgsql;

create trigger insert_test_trg
instead of insert on v_test
for each row execute function f_trg_insert_test();


Вариант с правилами (никакие функции не вызываются вообще):
Код: plsql
1.
2.
CREATE OR REPLACE RULE "_INSERT" AS ON INSERT TO v_test DO INSTEAD
INSERT INTO test(id, ctime) VALUES (NEW.id + 1, NEW.ctime);  -- при вставке только id значение NEW.ctime = NULL


Риторический вопрос : какой вариант проще и быстрее ?
...
Рейтинг: 0 / 0
INSRT ... VALUES (DEFAULT)
    #40009080
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cyrax_02
Вариант с триггерами (на каждой вставляемой строке вызывается триггерная функция, и даже не SQL , а более тяжёлая pgplSQL ):
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
create or replace function f_trg_insert_test() returns trigger as $$
declare
begin
  NEW.id := NEW.id+1;
  insert into test (id, ctime) select NEW.*;
  return NEW;
end;
$$ language plpgsql;

create trigger insert_test_trg
instead of insert on v_test
for each row execute function f_trg_insert_test();


Вариант с правилами (никакие функции не вызываются вообще):
Код: plsql
1.
2.
CREATE OR REPLACE RULE "_INSERT" AS ON INSERT TO v_test DO INSTEAD
INSERT INTO test(id, ctime) VALUES (NEW.id + 1, NEW.ctime);  -- при вставке только id значение NEW.ctime = NULL


Риторический вопрос : какой вариант проще и быстрее ?



На абсолютно любой мыслимой задаче - глубоко пофигу а реализация с триггером намного понятнее и проще в обслуживании и модификации.

Если же у вас действительно важна разница в скорости этих реализаций (100.000insert/s в одну таблицу)
то вам надо
1)вообще через сишную хранимку вставлять и не извращаться с записью в view вообще
или
2)подумать что это скорее всего не задача для реляционной базы...


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
INSRT ... VALUES (DEFAULT)
    #40009081
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cyrax_02

Возможны 2 реализации:
1 ) Если среди вставляемых полей некоторое поле отсутствует, внутри триггерной функции NEW.ctime должно иметь значение не NULL, а табличный DEFAULT для этого поля
2 ) NEW.ctime должно принимать некоторое специальное значение, отличное от NULL, соответствующее отсутствию значения во входных данных

Судя по всему, в PostgreSQL не реализован ни один из этих вариантов. В итоге мы имеем нерешённую проблему, когда при вставке в таблицу отсутствующего значения NEW.ctime = NULL, при этом невозможно определить, вставляется значение NULL или значение отсутствует (данное поле не сохраняется). А это разные ситуации.


Оба варианта не возможны архитектурно в принципе без критического обьема переделки кода...
Если вам оно сильно чешется - patch welcome
Но 90% что его завернут потому что визгу много а шерсти мало (в смысле патч очень большой инвазивный и меняющий уже существующее поведение но особо никому не нужный).

Первый еще и не дает возможность в before insert триггере понять что от insert поле таки не пришло (и отличить от вставки DEFAULT значения явной) и что то с этим сделать - то есть получить зеркальную проблему от той что вы пытаетесь решить (и не факт что она приятнее).
А второй - полный ад в реализации с переписыванием кучи кода.


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
12 сообщений из 12, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / INSRT ... VALUES (DEFAULT)
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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