У меня есть огромная таблица, которую нам нужно разбивать на разделы ежемесячно. Эта таблица в настоящее время является дочерней по отношению к другой таблице. Я пытаюсь создать раздел на этой таблице, и эти разделы будут унаследованы от исходной родительской таблицы. Я создал триггер и функцию, а старая дочерняя таблица содержит триггер для создания разделов.
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, и ошибка осталась прежней.
Примечание. Эта ошибка возникает при самой первой вставке, и из-за этой ошибки не создаются разделы.