Postgres触发不起作用

时间:2018-05-07 12:17:12

标签: postgresql database-partitioning database-trigger

我正在使用Postgres版本9.6

我有items_prt表,我想在字段上添加分区处理:

updated_at

所以我构建了这个功能。 目的是将行插入或更新到匹配的分区(年份分区) 并创建分区,如果它不存在。

插入效果很好,但更新不起作用......

我收到新值与旧分区不匹配的错误..

编辑:

我在网上发现了这个:

  

此处显示的方案假设a的分区键列   行永远不会改变,或者至少没有改变到足以要求它   移动到另一个分区。试图这样做的更新   由于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;

0 个答案:

没有答案