Vous mélangez double precision
sortie de date_part()
avec text '-'
. Cela n'a aucun sens pour PostgreSQL. Vous auriez besoin d'un cast explicite en text
. Mais il existe un moyen beaucoup plus simple de faire tout cela :
startdate:=date_part('year',to_timestamp(NEW.date))
||'-'||date_part('month',to_timestamp(NEW.date))
||'-'||date_part('day',to_timestamp(NEW.date));
Utilisez à la place :
startdate := to_char(NEW.date, 'YYYY-MM-DD');
Cela n'a aucun sens non plus :
EXECUTE 'CREATE TABLE $1 (
CHECK (date >= DATE $2 AND date < DATE $3 )
) INHERITS (pings)' USING quote_ident(tablename),startdate,enddate;
Vous ne pouvez fournir des valeurs qu'avec le USING
clause. Lire le manuel ici . Essayez plutôt :
EXECUTE 'CREATE TABLE ' || quote_ident(tablename) || ' (
CHECK ("date" >= ''' || startdate || ''' AND
"date" < ''' || enddate || '''))
INHERITS (ping)';
Ou mieux encore, utilisez le format format()
. Voir ci-dessous.
Aussi, comme @a_horse a répondu :Vous devez mettre vos valeurs de texte entre guillemets simples.
Similaire ici :
EXECUTE 'INSERT INTO $1 VALUES (NEW.*)' USING quote_ident(tablename);
Au lieu de cela :
EXECUTE 'INSERT INTO ' || quote_ident(tablename) || ' VALUES ($1.*)'
USING NEW;
Réponse connexe :
A part :bien que "date" soit autorisé pour un nom de colonne dans PostgreSQL, il s'agit d'un mot réservé dans chaque standard SQL . Ne nommez pas votre colonne "date", cela conduit à des erreurs de syntaxe déroutantes.
Démo de travail complète
CREATE TABLE ping (ping_id integer, the_date date);
CREATE OR REPLACE FUNCTION trg_ping_partition()
RETURNS trigger AS
$func$
DECLARE
_tbl text := to_char(NEW.the_date, '"ping_"YYYY_DDD_') || NEW.ping_id;
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'public' -- your schema
AND c.relname = _tbl
AND c.relkind = 'r') THEN
EXECUTE format('CREATE TABLE %I (CHECK (the_date >= %L AND
the_date < %L)) INHERITS (ping)'
, _tbl
, to_char(NEW.the_date, 'YYYY-MM-DD')
, to_char(NEW.the_date + 1, 'YYYY-MM-DD')
);
END IF;
EXECUTE 'INSERT INTO ' || quote_ident(_tbl) || ' VALUES ($1.*)'
USING NEW;
RETURN NULL;
END
$func$ LANGUAGE plpgsql SET search_path = public;
CREATE TRIGGER insbef
BEFORE INSERT ON ping
FOR EACH ROW EXECUTE PROCEDURE trg_ping_partition();
-
Mise à jour : Les versions ultérieures de Postgres ont des moyens plus élégants de vérifier si une table existe :
-
to_char()
peut prendre unedate
comme$1
. C'est converti entimestamp
automatiquement.
Le manuel sur les fonctions date/heure . -
(Facultatif)
SET
lesearch_path
pour la portée de votre fonction afin d'éviter toute mauvaise conduite avec unsearch_path
modifié réglage. -
Plusieurs autres simplifications et améliorations. Comparez le code.
Essais :
INSERT INTO ping VALUES (1, now()::date);
INSERT INTO ping VALUES (2, now()::date);
INSERT INTO ping VALUES (2, now()::date + 1);
INSERT INTO ping VALUES (2, now()::date + 1);