Postgres триггер не работает - PullRequest
0 голосов
/ 07 мая 2018

Я использую Postgres версии 9.6

У меня есть таблица items_prt, и я хочу добавить обработку разделов в поле:

updated_at

Так что я строю эту функцию. Цель состоит в том, чтобы вставить или обновить строку в соответствующем разделе (раздел для года) и создайте раздел, если он не существует.

Вставка работает отлично, но обновление просто не работает ...

Я получаю сообщение об ошибке, что новое значение не соответствует старому разделу.

EDIT:

Я нашел это в сети:

Схемы, показанные здесь, предполагают, что столбец (и) ключа разделения строка никогда не изменяется, или, по крайней мере, не изменяется достаточно, чтобы требовать перейти в другой раздел. ОБНОВЛЕНИЕ, которое пытается сделать это, будет не удается из-за ограничений CHECK. Если вам нужно справиться с таким В некоторых случаях вы можете поместить подходящие триггеры обновления в таблицы разделов, но это значительно усложняет управление структурой.

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

Мне просто кажется, что при простом удалении из старого раздела и вставке в новый раздел нужно это решить ..

Как правильно это сделать?

--The error:
SQL Error [23514]: ERROR: new row for relation "items_prt_y2018" violates check constraint "items_prt_y2018_updated_at_check"
  Detail: Failing row contains (99887766, null, null, null, 2019-05-07 15:33:44.431274, null, null, 0, null, 0, null, 0, null, null, null, null, f, null, null, null, null, 0, 0, null, null, null, null, null, null, null, null, null, f, null, null, null, null, null).
  SQL Error [23514]: ERROR: new row for relation "items_prt_y2018" violates check constraint "items_prt_y2018_updated_at_check"
  Detail: Failing row contains (99887766, null, null, null, 2019-05-07 15:33:44.431274, null, null, 0, null, 0, null, 0, null, null, null, null, f, null, null, null, null, 0, 0, null, null, null, null, null, null, null, null, null, f, null, null, null, null, null).
    SQL Error [23514]: ERROR: new row for relation "items_prt_y2018" violates check constraint "items_prt_y2018_updated_at_check"
  Detail: Failing row contains (99887766, null, null, null, 2019-05-07 15:33:44.431274, null, null, 0, null, 0, null, 0, null, null, null, null, f, null, null, null, null, 0, 0, null, null, null, null, null, null, null, null, null, f, null, null, null, null, null).
      SQL Error [23514]: ERROR: new row for relation "items_prt_y2018" violates check constraint "items_prt_y2018_updated_at_check"
  Detail: Failing row contains (99887766, null, null, null, 2019-05-07 15:33:44.431274, null, null, 0, null, 0, null, 0, null, null, null, null, f, null, null, null, null, 0, 0, null, null, null, null, null, null, null, null, null, f, null, null, null, null, null).
        ERROR: new row for relation "items_prt_y2018" violates check constraint "items_prt_y2018_updated_at_check"
  Detail: Failing row contains (99887766, null, null, null, 2019-05-07 15:33:44.431274, null, null, 0, null, 0, null, 0, null, null, null, null, f, null, null, null, null, 0, 0, null, null, null, null, null, null, null, null, null, f, null, null, null, null, null).
        ERROR: new row for relation "items_prt_y2018" violates check constraint "items_prt_y2018_updated_at_check"
  Detail: Failing row contains (99887766, null, null, null, 2019-05-07 15:33:44.431274, null, null, 0, null, 0, null, 0, null, null, null, null, f, null, null, null, null, 0, 0, null, null, null, null, null, null, null, null, null, f, null, null, null, null, null).

-- The constraint of partition:
CREATE TABLE public.items_prt_y2018 (
    CONSTRAINT items_prt_y2018_updated_at_check CHECK (((updated_at >= '2018-01-01'::date) AND (updated_at < '2019-01-01'::date)))
)
INHERITS (public.items_prt)
WITH (
    OIDS=FALSE
) ;

-- table DDL
CREATE TABLE public.items_prt (
    id serial NOT NULL,
    "desc" text NULL,
    user_id int4 NULL,
    created_at timestamp NULL,
    updated_at timestamp NULL,
    workflow_state varchar(255) NULL,
    transaction_type int4 NULL,
    priority int4 NULL DEFAULT 0,
    state_changed_at timestamp NULL,
    item_status int4 NULL DEFAULT 0,
    item_type_id int4 NULL,
    reject_reason int4 NULL DEFAULT 0,
    public_id varchar(255) NULL,
    headline varchar(255) NULL,
    buyers_invoice_sent bool NULL,
    initial_transaction_type int4 NULL,
    high_value_diamond bool NULL DEFAULT false,
    user_estimation text NULL,
    last_reimbursement_date date NULL,
    bogus bool NULL,
    bundle_id int4 NULL,
    value_category int4 NULL DEFAULT 0,
    shipment_cost float8 NULL DEFAULT 0,
    grading_by_company_id int4 NULL,
    arrived_at timestamp NULL,
    reserve_price float8 NULL,
    trade_in bool NULL,
    competition int4 NULL,
    current_item_location_name varchar(255) NULL,
    current_location_id int4 NULL,
    submitted_from varchar(255) NULL,
    store_id int4 NULL,
    was_reserve_price_changed bool NULL DEFAULT false,
    future_lead_id int4 NULL,
    referrer_id int4 NULL,
    approve_unmount_stone bool NULL,
    full_reserve_price float8 NULL,
    negotiation_minimum_price float8 NULL,
    CONSTRAINT items_prt_pkey PRIMARY KEY (id)
)
WITH (
    OIDS=FALSE
) ;


-- function for the trigger
CREATE OR REPLACE FUNCTION public.sf_items_prt_insert_update()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$

    -- get the new year and the next year into variables
    declare v_year varchar(100) :=extract (year from new.updated_at);
    declare v_next_year varchar(100) :=extract (year from new.updated_at + interval '1 year');

BEGIN

    -- create new partition for the entered year if it doesn't exists yet
    execute
    'CREATE TABLE if not exists items_prt_y' || v_year || '(
    CHECK ( updated_at >= DATE ''' || v_year || '-01-01'' AND updated_at < DATE ''' || v_next_year || '-01-01'' )
) INHERITS (items_prt);';

    -- insert the new row if this is a new row
    if (TG_OP = 'INSERT') then
        -- insert the new row into the new partition
        execute 'insert into items_prt_y' || v_year || ' select ($1).*' using new;
    end;

    if (TG_OP = 'UPDATE') then
        if extract (year from new.updated_at) <> extract (year from old.updated_at) then

            execute immediate 'delete from items_prt where id = ' || old.id;

            -- insert the new row into the new partition
            execute 'insert into items_prt_y' || v_year || ' select ($1).*' using new;
    end;

    -- return null because we don't want the row will insert\update again after the trigger ends
    RETURN NULL;

END;
$function$;

-- trigger
CREATE TRIGGER trg_items_prt_insert_update
    before insert or update ON items_prt
    FOR EACH ROW EXECUTE PROCEDURE sf_items_prt_insert_update();

-- working insert
insert into items_prt (id, updated_at) values (99887766, now());

-- not working update
update items_prt set updated_at = now() 
+ interval '1 year' 
where id = 99887766;
...