Nous utilisons des cookies pour vous garantir la meilleure expérience sur notre site. Si vous continuez à utiliser ce dernier, nous considèrerons que vous acceptez l'utilisation des cookies. J'ai compris ! ou En savoir plus !.
banniere

Le portail francophone de la géomatique


Toujours pas inscrit ? Mot de passe oublié ?
Nom d'utilisateur    Mot de passe              Toujours pas inscrit ?   Mot de passe oublié ?

Annonce

Rencontres QGIS 2025

L'appel à participation est ouvert jusqu'au 19 janvier 2025!

#1 Wed 21 May 2014 10:07

Géronimo
Participant occasionnel
Date d'inscription: 21 May 2014
Messages: 14

pl/pgsql modifier une table par une boucle

Bonjour à tous !!!

Je suis nouveau sur ce forum ainsi que dans la programmation en pl/pgsql. Je travail à partir de PostgreSQL 9.3.
Je viens requérir votre aide, parce que je n'arrive pas à trouver ce que je ne fais pas bien dans mon code.

Mon but, comme l'indique le titre est de modifier une table par l'utilisation de boucles, d'où le choix de pl/pgsql.
J'ai une table attributaire (290 lignes) qui renseigne des tronçons hydrographiques sur ma zone d'étude. Elle est composée de plusieurs colonne, dont une nommée "pkhexut". Cette colonne a la particularité de contenir 90 lignes avec la valeur 1000000. Je veux donc, par l'utilisation de boucles dans pl/pgsql, modifier ma table initiale pour qu'elle n'affiche plus que les 90 dites lignes. Je sais qu'avec une simple requête SQL, je peux avoir ce résultat très rapidement, mais je veux absolument le faire par l'intermédiaire de boucles, puisque je vais être amené à utiliser ces traitements afin d'effectuer des actions plus complexes qui les nécessitent nécessairement.

Ainsi, j'arrive sur deux cas. Pour le premier, j'écris la requête à l'intérieur de la boucle du FOREACH, comme suit :

Code:

CREATE OR REPLACE FUNCTION essai()
    RETURNS TABLE (ess_gid int, id_nd_ini cours_d_eau_par_noeuds_hydro_2.id_nd_ini%TYPE, id_nd_fin cours_d_eau_par_noeuds_hydro_2.id_nd_fin%TYPE,
geom cours_d_eau_par_noeuds_hydro_2.geom%TYPE, pkhexut cours_d_eau_par_noeuds_hydro_2.pkhexut%TYPE) AS
    $BODY$
    DECLARE
     pkhexut cours_d_eau_par_noeuds_hydro_2.pkhexut%TYPE;
     pkhtest numeric :=1000000;
    BEGIN
        IF (pkhexut is NOT NULL) THEN
         FOREACH pkhtest in ARRAY pkhexut
         LOOP
            RETURN QUERY SELECT row_number()OVER()::integer AS ess_gid, conh.id_nd_ini, conh.id_nd_fin, conh.geom, conh.pkhexut
            FROM cours_d_eau_par_noeuds_hydro_2 as conh
            ORDER BY ess_gid;
        END LOOP;
        END IF;
    END;
    $BODY$
LANGUAGE plpgsql;

Et lorsque j'exécute le "select * from essai()",  il me renvoie un tableau vide avec seulement le nom des colonnes.

Pour le deuxième cas, j'écris la requête à l'extérieur des boucles, comme suit :

Code:

CREATE OR REPLACE FUNCTION essai()
    RETURNS TABLE (ess_gid int, id_nd_ini cours_d_eau_par_noeuds_hydro_2.id_nd_ini%TYPE, id_nd_fin cours_d_eau_par_noeuds_hydro_2.id_nd_fin%TYPE,
geom cours_d_eau_par_noeuds_hydro_2.geom%TYPE, pkhexut cours_d_eau_par_noeuds_hydro_2.pkhexut%TYPE) AS
    $BODY$
    DECLARE
     pkhexut cours_d_eau_par_noeuds_hydro_2.pkhexut%TYPE;
     pkhtest numeric :=1000000;
    BEGIN
        IF (pkhexut is NOT NULL) THEN
         FOREACH pkhtest in ARRAY pkhexut
         LOOP
        END LOOP;
        END IF;
    RETURN QUERY SELECT row_number()OVER()::integer AS ess_gid, conh.id_nd_ini, conh.id_nd_fin, conh.geom, conh.pkhexut
    FROM cours_d_eau_par_noeuds_hydro_2 as conh
    ORDER BY ess_gid;
    END;
    $BODY$
LANGUAGE plpgsql;

Et là, lorsque j'exécute "select * from essai()", il me renvoie un tableau avec tous les noms des colonnes, mais avec toutes les lignes de la table "cours_d_eau_par_noeuds_hydro_2" alors que je ne lui ai demandé que les lignes où les valeurs de la colonne "pkhexut" sont égales à 1000000. Du coup, il me renvoie un tableau à 279 lignes au lieu d'un tableau à 90 lignes...

J'ai vraiment besoin de savoir comment modifier une table avec des boucles, même pour ce cas simple que je pourrais résoudre dans une simple requête SQL en rajoutant une ligne : "WHERE conh.pkhexut=1000000". Mais c'est pour, plus tard, effectuer des traitements complexes qui exigent l'intervention de boucle. Ainsi, si je sais comment modifier une table avec des boucles simples, j'aurais des pistes pour le faire avec des boucles complexes.

Je vous remercie d'avance pour vos futures réponses.

Hors ligne

 

#2 Wed 21 May 2014 15:12

Géronimo
Participant occasionnel
Date d'inscription: 21 May 2014
Messages: 14

Re: pl/pgsql modifier une table par une boucle

Ca y est !!!

J'ai trouvé la réponse à mon problème ! Et tout seul en plus. J'ai parcouru des dizaines de forums, de cours et de tuto en français et en anglais et j'ai enfin trouvé comment modifier une table par des boucles !!!

Voici le script :

Code:

CREATE OR REPLACE FUNCTION essai()
    RETURNS TABLE (ess_gid int, id_nd_ini cours_d_eau_par_noeuds_hydro_2.id_nd_ini%TYPE, id_nd_fin cours_d_eau_par_noeuds_hydro_2.id_nd_fin%TYPE,
geom cours_d_eau_par_noeuds_hydro_2.geom%TYPE, pkhexut cours_d_eau_par_noeuds_hydro_2.pkhexut%TYPE) AS
    $BODY$
    DECLARE
    tables record;
    BEGIN
    FOR tables IN (SELECT row_number()OVER()::integer AS ess_gid, conh.id_nd_ini, conh.id_nd_fin, conh.geom, conh.pkhexut
            FROM cours_d_eau_par_noeuds_hydro_2 as conh
            ORDER BY ess_gid) LOOP
        ess_gid := tables.ess_gid ; id_nd_ini := tables.id_nd_ini ; id_nd_fin := tables.id_nd_fin ;
        geom := tables.geom ; pkhexut := tables.pkhexut ;
        If pkhexut = 1000000 then
        RETURN NEXT;
        END IF;
        END LOOP;
    END;
    $BODY$
LANGUAGE plpgsql;

Et là, ça me retourne le tableau avec les colonnes que je lui demande et les 90 lignes correspondant à la valeur 1000000 de la colonne pkhexut.


Bon, maintenant il me reste à faire les traitements complexes qu'impliquent mon projet... Et ce sera bien ça le plus dur !
Je posterai d'ailleurs sûrement dans le futur, ou peut-être pas.

Comment signaler ce sujet comme résolu ?

A bientôt !

Hors ligne

 

#3 Wed 21 May 2014 17:57

Nicolas Ribot
Membre
Lieu: Toulouse
Date d'inscription: 9 Sep 2005
Messages: 1554

Re: pl/pgsql modifier une table par une boucle

Bonsoir,

La fonction proposée ne modifie pas de table: elle liste juste des lignes qui correspondent à une condition.

S'il est intéressant (voire essentiel) de maitriser les boucles et le langage Pl/PgSQL, je vous décourage de boucler sur tous les résultats d'une table et d'ajouter des tests if pour tester des valeurs:
PGSQL permet d'ecrire directement du SQL, avec des conditions ou des tests dynamiques (par ex issus de valeurs de paramètres).
Ce SQL peut contenir des SELECT, UPDATE, INSERT, etc.

Par exemple dans votre cas: select ... from cours_d_eau_par_noeuds_hydro_2 where pkhexut = 1000000;

A quels types de traitements complexes pensez-vous ?

Nicolas

Hors ligne

 

#4 Wed 21 May 2014 19:30

Géronimo
Participant occasionnel
Date d'inscription: 21 May 2014
Messages: 14

Re: pl/pgsql modifier une table par une boucle

Nicolas Ribot,

Déjà merci à vous de m'avoir répondu.

Je sais que la fonction proposée ne modifie pas la table, mais elle propose des lignes que je peux lire par un select, puis enregistrer par un create view et enfin que je peux afficher sur ArcGIS pour me rendre compte du résultat sur la carte elle-même.

Je sais aussi que j'aurais pu avoir directement le résultat de la requête par le code : select ... from cours_d_eau_par_noeuds_hydro_2 where pkhexut = 1000000;
Je l'ai déjà fait par ailleurs, de plus. Mais je voulais absolument pouvoir exécuter cette requête en utilisant que des boucles, ceci afin de me servir de base pour mes traitements complexes futurs. Je vais donc vous expliquer ce que je recherche :

Je dois d'abord indiquer que je travaille sur la géologie.
J'ai donc deux tables :
- L'une appelée formation_silex contient toutes les zones de formation à silex. Il s'agit donc de polygones numérisés sur la carte géologique elle-même auxquels j'ai renseignés, sur la table attributaire un certains nombre de caractéristiques, dont celle qui nous intéresse, c'est à dire le numéro d'identifiant de chacune des zones de formations à silex.
- L'autre, appelée cours_d_eau_par_noeuds_hydro_2 est issue d'une jointure de 3 tables. La première était la table des tronçons hydrographiques, c'est-à-dire que chaque ligne correspondait à une polyligne représentant un tronçon hydrographique. Un tronçon hydro correspond à une partie d'un cours d'eau. Le découpage s'effectue en fonction des bassins versants. Donc il y a un tronçon par bassin versant. La seconde était la table des zones hydrographiques, c'est-à-dire des bassins versants eux-mêmes. La troisième était la table des noeuds_hydrographiques, c'est-à-dire que chaque extrémité des tronçons hydrographiques est représenté par un point avec une identification particulière. La jointure des 3 tables a donc donné la table cours_d_eau_par_noeuds_hydro_2 qui se base sur la géométrie des tronçons hydrographiques. A noté que pour simplifier les calculs dans un premier temps, je n'ai utilisé que les tronçons hydrographiques principaux des bassins versants. Il n'y a donc qu'un tronçon hydro par BV.
Sur cette table est renseigné, champ par champ : le code de la zone hydrographique (donc du bassin versant) (code_zone), le code du tronçon hydrographique lui même (code_hydro), le code du cours d'eau auquel appartient le tronçon hydrographique (c_cdo_hyd), le code du noeud hydrographique situé en amont du tronçon hydro (id_nd_ini), le code du noeud hydro situé en aval du tronçon (id_nd_fin), le nom du cours d'eau auqel appartient le tronçon hydro (toponyme1), l'identifiant de la zone de formation à silex (idf) et puis, bien sûr, la numérotation (gid) et la géométrie (geom).

Dans un premier temps, par une simple jointure spatiale, je fais correspondre pour chaque tronçon de la table cours_d_eau_par_noeuds_hydro_2 l'identifiant des zones de formations à silex qui sont traversés par ces tronçons hydro. Bon, ça c'est très facile à faire.

Mais dans un deuxième temps, et c'est là que vont intervenir les traitements complexes, je voudrais que les identifiants des zones de formation à silex qui se trouve sur le tronçon hydro qui les traverse (un tronçon hydro peut traverser plusieurs zones de formation) soient renseignés sur les tronçons hydro situés en aval. Puisque les silex se déplacent dans le sens du courant d'un cours d'eau.
Ainsi, j'avais pensé traduire en langage sql sur pl/pgsql la phrase suivante. Tant que l'identifiant du noeud hydro situé en aval du tronçon hydro (donc id_nd_fin) est égal à l'identifiant du noeud hydro situé en amont du tronçon hydro suivant (donc id_nd_fin), l'identifiant de la zone de formation à silex (idf) est renseigné au tronçon situé en aval.
A partir de là, il y a toujours des problèmes, mais que je pense les résoudre en fur et à mesure de mes tests, vu que maintenant, je sais quel base adopter pour utiliser les boucles. Pour vous exposer un de mes problèmes actuels, j'ai divisé la table cours_d_eau_par_noeuds_hydro_2 en deux autres tables. Elles contiennent toutes les deux toutes les colonnes sauf une. La première n'a pas la colonne id_nd_ini et la deuxième n'a pas id_nd_fin. Je peux ainsi réaliser des requêtes en demandant de faire la jointure pour id_nd_fin=id_nd_ini. Mais là où le problème réside, c'est que je ne sais pas comment indiquer au logiciel que l'ordre dans lequel sont écrites les lignes n'importe pas et qu'il cherche dans l'ensemble des tables si table1.id_nd_fin=table2.id_nd_ini

Voilà mon projet actuel. Il était au point mort depuis quelques jours et je viens de le débloquer par le script que j'ai écrit dans mon précédent message. Si vous avez quelque chose de mieux à me proposer, je suis tout à fait preneur et complètement ouvert. Sinon, je continuerai dans mon idée.

J'espère ne pas trop vous avoir abreuvé.

Merci encore pour votre réponse.

A plus tard, j'espère...

Hors ligne

 

Pied de page des forums

Powered by FluxBB