Vous n'êtes pas identifié(e).
Bonjour,
Je travaille dans les télécom et je souhaite diviser une table de câbles "CB" en x tables en fonction des x valeurs uniques du champ "mode_pose".
Après consultation des tutoriels et forums, j'ai rédigé en PL/pgSQL le code copié ci-dessous :
"""
CREATE OR REPLACE FUNCTION split_CB() RETURNS VARCHAR as $$
DECLARE
x VARCHAR;
BEGIN
FOR x IN SELECT DISTINCT CB."mode_pose"
FROM "syane_test"."CB" CB
LOOP
EXECUTE format('
DROP TABLE IF EXISTS syane_test.CB_'||x||';
CREATE TABLE syane_test.CB_'||x||' AS
SELECT *
FROM "syane_test"."CB" CB
WHERE CB."mode_pose" ='||quote_literal(x)||';');
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT split_CB();
"""
et je me suis heurté à un message d'erreur suivant :
"""
NOTICE: la table « cb_aerien » n'existe pas, poursuite du traitement
CONTEXT: instruction SQL «
DROP TABLE IF EXISTS syane_test.CB_AERIEN;
CREATE TABLE syane_test.CB_AERIEN AS
SELECT *
FROM "syane_test"."CB" CB
WHERE CB."mode_pose" ='AERIEN'; »
fonction PL/pgsql split_cb(), ligne 9 à EXECUTE
NOTICE: la table « cb_immeuble » n'existe pas, poursuite du traitement
CONTEXT: instruction SQL «
DROP TABLE IF EXISTS syane_test.CB_IMMEUBLE;
CREATE TABLE syane_test.CB_IMMEUBLE AS
SELECT *
FROM "syane_test"."CB" CB
WHERE CB."mode_pose" ='IMMEUBLE'; »
fonction PL/pgsql split_cb(), ligne 9 à EXECUTE
NOTICE: la table « cb_souterrain » n'existe pas, poursuite du traitement
CONTEXT: instruction SQL «
DROP TABLE IF EXISTS syane_test.CB_SOUTERRAIN;
CREATE TABLE syane_test.CB_SOUTERRAIN AS
SELECT *
FROM "syane_test"."CB" CB
WHERE CB."mode_pose" ='SOUTERRAIN'; »
fonction PL/pgsql split_cb(), ligne 9 à EXECUTE
ERREUR: le contrôle a atteint la fin de la fonction sans RETURN
CONTEXT: fonction PL/pgsql split_cb()
********** Erreur **********
ERREUR: le contrôle a atteint la fin de la fonction sans RETURN
État SQL :2F005
Contexte : fonction PL/pgsql split_cb()
"""
Pouvez-vous m'aider à résoudre cette erreur ?
Et si oui, dans la foulée, est-il possible d'intégrer aux nouvelles tables, la création en boucle de Contraintes de clé primaire ?
Merci par avance.
Bien cordialement.
Hors ligne
Bonjour
Bonjour,
"""
CREATE OR REPLACE FUNCTION split_CB() RETURNS VARCHAR as $$
[...]
END LOOP;END;
$$ LANGUAGE plpgsql;
"""et je me suis heurté à un message d'erreur suivant :
"""
ERREUR: le contrôle a atteint la fin de la fonction sans RETURN
CONTEXT: fonction PL/pgsql split_cb()
********** Erreur **********ERREUR: le contrôle a atteint la fin de la fonction sans RETURN
État SQL :2F005
Contexte : fonction PL/pgsql split_cb()"""
Pouvez-vous m'aider à résoudre cette erreur ?
Le message est assez parlant: votre fonction est déclarée comment retournant un varchar, et elle ne retourne rien. À priori changer la déclaration en "RETURNS void" devrait suffire, vu qu'il ne devrait pas être nécessaire de retourner une information.
Et si oui, dans la foulée, est-il possible d'intégrer aux nouvelles tables, la création en boucle de Contraintes de clé primaire ?
Il est possible de créer une table en copiant la définition ainsi que d'autres élément d'une autre table, mais la granularité serait dans votre cas de récupérer toutes les contraintes et pas uniquement la clé primaire. Vous pouvez consulter la documentation de CREATE TABLE (et non CREATE TABLE AS) à https://www.postgresql.org/docs/current … table.html notamment la partie "LIKE source_table [ like_option ... ]".
Cela dit, il serait beaucoup plus peformant de créer la ou les contraintes manuellement après avoir inséré les données, même si cela nécessitera un peu plus de code.
Sinon, pourquoi ne pas utiliser le partitionnement natif ?
Julien.
https://rjuju.github.io/
Hors ligne
Re-Bonjour,
Merci beaucoup rjuju pour votre aide avec notamment "RETURN void".
J'ai réussi à créer automatiquement mes x (ici : 3 dans mon exemple : "ARERIEN", "IMMEUBLE" et "SOUTERRAIN") tables issues de la division y compris avec la création en boucle des Contraintes de clés primaires.
Le code est le suivant :
"""
DROP FUNCTION IF EXISTS syane_test.split_CB();
CREATE FUNCTION syane_test.split_CB() RETURNS void as $$
DECLARE
x VARCHAR;
BEGIN
FOR x IN SELECT DISTINCT CB."mode_pose"
FROM "syane_test"."CB" CB
LOOP
EXECUTE format('
DROP TABLE IF EXISTS syane_test.CB_'||x||';
CREATE TABLE syane_test.CB_'||x||' AS
SELECT *
FROM "syane_test"."CB" CB
WHERE CB."mode_pose" ='||quote_literal(x)||';');
EXECUTE format('ALTER TABLE syane_test.CB_'||x||'
ADD CONSTRAINT '||x||'_pkey PRIMARY KEY("code_cb")');
END LOOP;
END;
$$ LANGUAGE plpgsql;
SELECT syane_test.split_CB();
"""
@rjuju : étant encore débutant sur le PL/pgSQL, j'ai trois petites questions complémentaires à titre informatif.
-1- Quand et pourquoi utilise-t-on l'instruction : EXECUTE format('requête SQL') ?
-2- Quand et pourquoi utilise-t-on la fonction : quote_literal() ?
Appliquée à la variable x dans mon exemple mais uniquement au sein de la clause WHERE et à l'intérieur de l'instruction EXECUTE format('requête SQL').
-3- À quoi correspond le type de variable "void" ?
Merci rjuju par avance pour vos précisions complémentaires et surtout surtout pour le "RETURN void" qui m'a débloqué.
Bien Cordialement.
Hors ligne
-1- Quand et pourquoi utilise-t-on l'instruction : EXECUTE format('requête SQL') ?
C'est nécessaire pour exécuter une requête "dynamique", comme par exemple avoir le nom d'une table qui dépend d'une variable.
-2- Quand et pourquoi utilise-t-on la fonction : quote_literal() ?
Appliquée à la variable x dans mon exemple mais uniquement au sein de la clause WHERE et à l'intérieur de l'instruction EXECUTE format('requête SQL').
À chaque fois que vous générez des requêtes dynamiques et que vous avez un literal pouvant contenir un peu tout. Cela permet d'éviter les erreurs ainsi que les injections SQL. Vous devriez également utiliser quote_ident() pour les identifiant (nom de table, schema etc).
-3- À quoi correspond le type de variable "void" ?
Ce n'est pas un type, cela indique que la fonction ne renvoie rien.
Julien.
https://rjuju.github.io/
Hors ligne
Merci beaucoup rjuju pour toutes vos informations !
Ah, une toute toute dernière question et je ne vous embête plus : j'utilise en local depuis 2019 et pour des migrations des bases de données SIG télécom du MCD Covage vers le MCD GraceTHD
le SGBDR PostgreSQL version 9.5/pgAdmin III . J'ai 63 bases de données dessus.
J'ai récemment installé les versions 13.7 et 14.4/pdAdmin 4 sur le poste de nouveaux collègues.
==> Pour installer la dernière (14.4), je dois supprimer la 9.5 et exporter préalablement un backup pour chacune des 63 bases de données ?
Merci beaucoup par avance (j'essayerai de ne plus vous retenir davantage)
Bien cordialement.
Philippe
Hors ligne
Le forum est justement là pour aider, n'hésitez pas à poser des questions si vous êtes bloqués
==> Pour installer la dernière (14.4), je dois supprimer la 9.5 et exporter préalablement un backup pour chacune des 63 bases de données ?
Plusieurs versions majeures (et même plusieurs instances d'une même version majeure) peuvent coexister sur la même machine sans que cela pose problème, du moment que chaque instance écoute sur un port différent (ou ne sont pas démarrées en même temps). La 9.5 est par contre très vieille, donc migrer toutes les données vers une version plus récente semble une bonné idée.
Vous pouvez faire cela soit en exportant chaque base une à une, soit en utilisant pg_upgrade (https://docs.postgresql.fr/14/pgupgrade.html ). pg_upgrade est plus compliqué à utiliser mais sera plus rapide, surtout si les bases sont volumineuses.
Julien.
https://rjuju.github.io/
Hors ligne
Merci rjuju pour ces informations : pg_upgrade
Je vais tester cela. C'est bien dans l'invite de commande de Windows qu'on lance ce code directement ?
--
Du coup, comme vous m'y avez incité, je vais "mentir" une fois suite à mon dernier message.
J'ai encore une question : la notion de séquence ?
j'ai cru comprendre qu'elle était utilisée pour incrémenter des ID (clé primaires par exemple)
mais je n'ai jamais eu besoin de les utiliser. PostgreSQL les crée automatiquement ?
Sur certaine grosses requête SQL qui génèrent la création d'une base (Tables et Champs selon un MCD comme dans les télécom : GraceTHD, Syane ou encore Covage) puis l'insertion des données, il y a des séquences rédigées
mais je ne sais pas à partir de quel moment/quelles conditions cette rédaction de séquences devient indispensable ?
Merci rjuju (en Julien, j'ai cru comprendre) par avance pour vos informations.
Hors ligne
Je vais tester cela. C'est bien dans l'invite de commande de Windows qu'on lance ce code directement ?
Tout à fait. Pensez à faire une sauvegarde du répertoire de données de l'ancienne version (une fois l'instance arrêté) avant de commencer, au cas où.
J'ai encore une question : la notion de séquence ?
j'ai cru comprendre qu'elle était utilisée pour incrémenter des ID (clé primaires par exemple)
mais je n'ai jamais eu besoin de les utiliser. PostgreSQL les crée automatiquement ?
Oui, c'est généralement utilisé pour des colonnes auto incrémentées. Postgres créera des séquences automatiquement avec des valeurs par défaut si vous créez une table avec un champ serial ou bigserial, ou pour des versions plus récentes GENERATED AS IDENTITY, mais vous pouvez les créer manuellement pour d'autres besoins.
Sur certaine grosses requête SQL qui génèrent la création d'une base (Tables et Champs selon un MCD comme dans les télécom : GraceTHD, Syane ou encore Covage) puis l'insertion des données, il y a des séquences rédigées
mais je ne sais pas à partir de quel moment/quelles conditions cette rédaction de séquences devient indispensable ?
Je ne comprends pas trop ce que vous entendez par "rédiger une séquence". Mais en gros, une séquence est utile quand on a besoin d'une clé technique pour identifier des lignes. Une séquence permet de garantir que 2 appels donneront deux résultats différents, ave pour conséquence qu'une table utilisant des séquence pourra avoir des numéro manquants. On peut utiliser à la place des uuid par exemple. Le résultat est plus ou moins le même, avec des compromis différents du fait de la différence entre les deux types de données (taille, valeur strictement monotone ou non etc).
Julien.
https://rjuju.github.io/
Hors ligne
Merci beaucoup rjuju/Julien pour toutes ces informations et surtout pour m'avoir débloqué au début de l'ensemble de cette discussion avec le "RETURN void".
Bien cordialement,
Philippe
Hors ligne