我有一张大桌子,我们需要每月进行分区。该表当前是另一个表的子级。我试图在此表上创建一个分区,这些分区将要从原始父表继承。我已经创建了触发器和函数,并且旧的子表保存了触发器以创建分区。
Tables:
parent_table (Partitioned tables are going to be inherited from this table)
old_child_table (This holds the trigger, code will try to insert here)
CREATE OR REPLACE FUNCTION temp.partition_insert_function()
RETURNS TRIGGER
AS $$
DECLARE
partition_month TEXT;
partition_schema TEXT;
partition_name TEXT;
start_of_month TEXT;
end_of_month TEXT;
BEGIN
partition_month := to_char(NEW.created_dtm,'YYYY_MM'); ---This column has a default of now() and it is of timestamp with timezone
partition_schema := 'temp';
partition_name := 'partition_' || partition_month;
start_of_month := to_char((NEW.created_dtm),'YYYY-MM'|| '-01');
end_of_month := to_char((NEW.created_dtm + interval '1 month'),'YYYY-MM'|| '-01');
EXECUTE format('INSERT INTO %I.%I VALUES($1.*) ON CONFLICT (primary_key) DO NOTHING', partition_schema, partition_name) using NEW;
---I want to try to insert first rather than checking every time if the partition exists or not.
RETURN NULL;
EXCEPTION WHEN SQLSTATE '42P01' THEN
RAISE NOTICE 'RELNAME %', TG_TABLE_NAME;
IF NOT EXISTS ---If the insert fails for above SQLSTATE then I want to check if the partition exists or not
(SELECT 1
FROM information_schema.tables
WHERE table_name = partition_name
AND table_schema = partition_schema)
THEN
EXECUTE 'CREATE TABLE ' || partition_schema || '.' || partition_name || ' (check (created_dtm >= ''' || start_of_month || ''' and created_dtm < ''' || end_of_month || ''' ), ' || 'LIKE temp.old_child_table INCLUDING ALL) INHERITS (temp.parent_table)';
EXECUTE 'ALTER TABLE ' || partition_schema || '.' || partition_name || ' OWNER TO owner';
EXECUTE 'GRANT SELECT ON TABLE ' || partition_schema || '.' || partition_name || ' TO user_ro';
EXECUTE 'GRANT INSERT, SELECT, UPDATE, DELETE ON TABLE ' || partition_schema || ' . ' || partition_name || ' TO user_rw';
EXECUTE 'ALTER TABLE ' || partition_schema || '.' || partition_name || ' ADD CONSTRAINT ' || partition_name || '_fkey1 FOREIGN KEY(random_key) REFERENCES temp.random(random_key)';
EXECUTE 'CREATE TRIGGER ' || partition_name || '_trigger1 BEFORE INSERT OR UPDATE ON ' || partition_schema || '.' || partition_name || ' FOR EACH ROW EXECUTE PROCEDURE temp.trigger_function()';
RAISE NOTICE 'A partition has been created %.%', partition_schema, partition_name;
RAISE NOTICE 'All FK constraints are created on %.%', partition_schema, partition_name;
RAISE NOTICE 'All necessary indices are created on %.%', partition_schema, partition_name;
RAISE NOTICE 'All triggers are created on %.%', partition_schema, partition_name;
END IF;
EXECUTE format('INSERT INTO %I.%I VALUES($1.*) ON CONFLICT (primary_key) DO NOTHING', partition_schema, partition_name) using NEW;
RETURN NULL;
END
$$
LANGUAGE plpgsql;
CREATE TRIGGER insert_trigger
BEFORE INSERT
ON temp.old_child_table
FOR EACH ROW
EXECUTE PROCEDURE temp.partition_insert_function();
It gives me below error;
ERROR: new row for relation "partition_2018_04" violates check constraint "partition_2018_04_created_dtm_check"
我还尝试在old_child_table上创建视图并在该视图上创建触发器,但这给了我同样的错误。理想情况下,我们想在视图上创建它,因为我们想获取返回的primary_key。在函数中,我还尝试替换RETURN NULL或RETURN NEW,并且错误仍然相同。
注意:在第一个插入本身上会引发此错误,并且由于该错误而不会创建任何分区。