分区时 PostgreSQL 9.5 Insert/Update table
PostgreSQL 9.5 Insert/Update while partitioning table
我需要在分区 table 中实现更新(通过 ON CONFLICT())行。
到目前为止,我的尝试:
Table创作:
CREATE TABLE public.my_tbl
(
goid character varying(255) NOT NULL,
timestamps timestamp without time zone[],
somenumber numeric[],
CONSTRAINT my_tbl_pkey PRIMARY KEY (goid)
)
WITH (
OIDS=FALSE
);
ALTER TABLE public.my_tbl
OWNER TO postgres;
Table 序列:
CREATE SEQUENCE public.fixations_data_pkey_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
ALTER TABLE public.fixations_data_pkey_seq
OWNER TO postgres;
Table 分区触发器,创建新的 table 名称为 "table_YYYY_MM_DD",其中 "YYYY_MM_DD" - 当前日期(查询执行日期):
CREATE OR REPLACE FUNCTION public.my_tbl_insert_trigger()
RETURNS trigger AS
$BODY$
DECLARE
table_master varchar(255) := 'my_tbl';
table_part varchar(255) := '';
BEGIN
-- Partition table name --------------------------------------------------
table_part := table_master
|| '_' || DATE_PART( 'year', NOW() )::TEXT
|| '_' || DATE_PART( 'month', NOW() )::TEXT
|| '_' || DATE_PART( 'day', NOW() )::TEXT;
-- Check if partition exists --------------------------------
PERFORM
1
FROM
pg_class
WHERE
relname = table_part
LIMIT
1;
-- If not exist, create new one --------------------------------------------
IF NOT FOUND
THEN
-- Create parition, which inherits master table --------------------------
EXECUTE '
CREATE TABLE ' || table_part || '
(
goid character varying(255) NOT NULL DEFAULT nextval(''' || table_master || '_pkey_seq''::regclass),
CONSTRAINT ' || table_part || '_pkey PRIMARY KEY (goid)
)
INHERITS ( ' || table_master || ' )
WITH ( OIDS=FALSE )';
-- Create indices for current table-------------------------------
EXECUTE '
CREATE INDEX ' || table_part || '_adid_date_index
ON ' || table_part || '
USING btree
(goid)';
END IF;
-- Insert row into table (without ON CONFLICT)--------------------------------------------
EXECUTE '
INSERT INTO ' || table_part || '
SELECT ( (' || QUOTE_LITERAL(NEW) || ')::' || TG_RELNAME || ' ).*';
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION public.my_tbl_insert_trigger()
OWNER TO postgres;
CREATE TRIGGER my_tbl_insert_trigger
BEFORE INSERT
ON my_tbl
FOR EACH ROW
EXECUTE PROCEDURE my_tbl_insert_trigger();
之后我可以将新行插入 table:
INSERT INTO my_tbl (goid, timestamps, somenumber)
VALUES ('qwe123SSsssa3', '{"2016-11-16 00:00:00", "2016-11-16 01:00:00"}', '{3, 12333}')
但是当我尝试执行 UPSERT 时:
INSERT INTO my_tbl (goid, timestamps, somenumber)
VALUES ('qwe123SSsssa3', '{"2016-11-16 02:00:00"}', '{999}')
ON CONFLICT (goid)
DO UPDATE
SET timestamps=array_append(my_tbl.timestamps::timestamp[], '2016-11-16 02:00:00'),
somenumber=array_append(my_tbl.somenumber,'999');
我收到 DUPLICATE PKEY 错误。
我想,我必须将 ON CONFLICT 添加到触发器函数中的第三个 EXECUTE。但是我应该怎么做呢?
好吧,我已将第三个 EXECUTE 更改为:
-- Insert row into table (with ON CONFLICT)--------------------------------------------
EXECUTE '
INSERT INTO ' || table_part || '
SELECT ( (' || QUOTE_LITERAL(NEW) || ')::' || TG_RELNAME || ' ).*
ON CONFLICT (goid)
DO UPDATE
SET timestamps=' || table_part || '.timestamps::timestamp[] || ' || QUOTE_LITERAL(NEW.timestamps) || ',
somenumber=' || table_part || '.somenumber::numeric[] || ' || QUOTE_LITERAL(NEW.somenumber) || '
';
RETURN NULL;
现在,当我执行查询时:
INSERT INTO my_tbl (goid, timestamps, somenumber)
VALUES ('potato_1', ARRAY['2016-11-16 12:00:00', '2016-11-16 15:00:00']::timestamp[], ARRAY[223, 211]::numeric[]);
没有任何错误,并且如我所料扩展了数组类型的列
我可以承认这是一个肮脏的解决方案,但它似乎有效。
如果有人有更好的解决方案,我会很乐意看看。
我需要在分区 table 中实现更新(通过 ON CONFLICT())行。
到目前为止,我的尝试:
Table创作:
CREATE TABLE public.my_tbl
(
goid character varying(255) NOT NULL,
timestamps timestamp without time zone[],
somenumber numeric[],
CONSTRAINT my_tbl_pkey PRIMARY KEY (goid)
)
WITH (
OIDS=FALSE
);
ALTER TABLE public.my_tbl
OWNER TO postgres;
Table 序列:
CREATE SEQUENCE public.fixations_data_pkey_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
ALTER TABLE public.fixations_data_pkey_seq
OWNER TO postgres;
Table 分区触发器,创建新的 table 名称为 "table_YYYY_MM_DD",其中 "YYYY_MM_DD" - 当前日期(查询执行日期):
CREATE OR REPLACE FUNCTION public.my_tbl_insert_trigger()
RETURNS trigger AS
$BODY$
DECLARE
table_master varchar(255) := 'my_tbl';
table_part varchar(255) := '';
BEGIN
-- Partition table name --------------------------------------------------
table_part := table_master
|| '_' || DATE_PART( 'year', NOW() )::TEXT
|| '_' || DATE_PART( 'month', NOW() )::TEXT
|| '_' || DATE_PART( 'day', NOW() )::TEXT;
-- Check if partition exists --------------------------------
PERFORM
1
FROM
pg_class
WHERE
relname = table_part
LIMIT
1;
-- If not exist, create new one --------------------------------------------
IF NOT FOUND
THEN
-- Create parition, which inherits master table --------------------------
EXECUTE '
CREATE TABLE ' || table_part || '
(
goid character varying(255) NOT NULL DEFAULT nextval(''' || table_master || '_pkey_seq''::regclass),
CONSTRAINT ' || table_part || '_pkey PRIMARY KEY (goid)
)
INHERITS ( ' || table_master || ' )
WITH ( OIDS=FALSE )';
-- Create indices for current table-------------------------------
EXECUTE '
CREATE INDEX ' || table_part || '_adid_date_index
ON ' || table_part || '
USING btree
(goid)';
END IF;
-- Insert row into table (without ON CONFLICT)--------------------------------------------
EXECUTE '
INSERT INTO ' || table_part || '
SELECT ( (' || QUOTE_LITERAL(NEW) || ')::' || TG_RELNAME || ' ).*';
RETURN NULL;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION public.my_tbl_insert_trigger()
OWNER TO postgres;
CREATE TRIGGER my_tbl_insert_trigger
BEFORE INSERT
ON my_tbl
FOR EACH ROW
EXECUTE PROCEDURE my_tbl_insert_trigger();
之后我可以将新行插入 table:
INSERT INTO my_tbl (goid, timestamps, somenumber)
VALUES ('qwe123SSsssa3', '{"2016-11-16 00:00:00", "2016-11-16 01:00:00"}', '{3, 12333}')
但是当我尝试执行 UPSERT 时:
INSERT INTO my_tbl (goid, timestamps, somenumber)
VALUES ('qwe123SSsssa3', '{"2016-11-16 02:00:00"}', '{999}')
ON CONFLICT (goid)
DO UPDATE
SET timestamps=array_append(my_tbl.timestamps::timestamp[], '2016-11-16 02:00:00'),
somenumber=array_append(my_tbl.somenumber,'999');
我收到 DUPLICATE PKEY 错误。
我想,我必须将 ON CONFLICT 添加到触发器函数中的第三个 EXECUTE。但是我应该怎么做呢?
好吧,我已将第三个 EXECUTE 更改为:
-- Insert row into table (with ON CONFLICT)--------------------------------------------
EXECUTE '
INSERT INTO ' || table_part || '
SELECT ( (' || QUOTE_LITERAL(NEW) || ')::' || TG_RELNAME || ' ).*
ON CONFLICT (goid)
DO UPDATE
SET timestamps=' || table_part || '.timestamps::timestamp[] || ' || QUOTE_LITERAL(NEW.timestamps) || ',
somenumber=' || table_part || '.somenumber::numeric[] || ' || QUOTE_LITERAL(NEW.somenumber) || '
';
RETURN NULL;
现在,当我执行查询时:
INSERT INTO my_tbl (goid, timestamps, somenumber)
VALUES ('potato_1', ARRAY['2016-11-16 12:00:00', '2016-11-16 15:00:00']::timestamp[], ARRAY[223, 211]::numeric[]);
没有任何错误,并且如我所料扩展了数组类型的列
我可以承认这是一个肮脏的解决方案,但它似乎有效。
如果有人有更好的解决方案,我会很乐意看看。