我正在使用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;