PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 19/05/2014 17:10:37

Géronimo
Membre

modification d'une table

Bonjour à tous,


Je suis nouveau sur ce forum, mais aussi pour la programmation en pl/pgSQL. Avant d'écrire ce message, j'ai parcouru le forum par l'option recherche, mais je n'ai pas trouvé la solution à mon problème qui me parait pourtant basique.


Comme indiqué dans le sujet du message, je veux pouvoir modifier ma table sur pl/pgSQL pour ensuite l'afficher par un CREATE VIEW basique sur postgresql.
Ce que je veux précisément faire dans la fonction, c'est d'afficher les colonnes "ess_gid", "id_nd_ini", "id_nd_fin", "geom", "pkhexut" de la table "cours_d_eau_par_noeuds_hydro_2" lorsque les valeurs de la colonne pkhexut sont égales à 1000000. Je sais que c'est faisable directement sur PostgreSQL, mais je dois le réussir cette étape sur pl/pgSQL, parce que je ferais, plus tard, des traitements qui nécessiteront absolument ce langage, par l'utilisation de boucles. Je teste donc une boucle "simple" afin de me lancer plus tard dans des boucles plus complexes.


Après de multiples et nombreuses recherches sur le net, j'en suis arrivé à ce script :

DROP FUNCTION essai() CASCADE

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
	 totdiff integer;
	 pkhexut numeric[];
	 pkh numeric;
	 pkhtest numeric :=1000000;;
	BEGIN
	 totdiff:=totdiff+1;
	 pkhexut[totdiff]:=pkh;
		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;

CREATE or replace VIEW essai1 as
select * from essai()

Lorsque je teste la fonction en elle-même, il m'est indiqué :

NOTICE:  référence de type cours_d_eau_par_noeuds_hydro_2.id_nd_ini%TYPE convertie en numeric
NOTICE:  référence de type cours_d_eau_par_noeuds_hydro_2.id_nd_fin%TYPE convertie en numeric
NOTICE:  référence de type cours_d_eau_par_noeuds_hydro_2.geom%TYPE convertie en geometry
NOTICE:  référence de type cours_d_eau_par_noeuds_hydro_2.pkhexut%TYPE convertie en numeric

La requête a été exécutée avec succès en 12 ms, mais ne renvoie aucun résultat.

Donc, pas de problème. Par contre, lorsque je teste la ligne

select * from essai()

, il m'est indiqué :

ERREUR:  un indice de tableau dans une affectation ne peut pas être NULL
CONTEXT:  fonction PL/pgsql essai(), ligne 9 à affectation
********** Erreur **********

ERREUR: un indice de tableau dans une affectation ne peut pas être NULL
État SQL :22004
Contexte : fonction PL/pgsql essai(), ligne 9 à affectation

Il m'indique que l'affectation ne peut pas être NULL alors que je précise justement IS NOT NULL à cet endroit.
Quel est le problème ?
Est-ce que j'utilise vraiment la bonne démarche pour ce que je veux faire ?


Merci d'avance de vos réponses...

Hors ligne

#2 19/05/2014 23:50:25

gleu
Administrateur

Re : modification d'une table

Le problème n'est pas cette ligne mais la précédente :

pkhexut[totdiff]:=pkh;

pkh est NULL, or vous ne pouvez pas mettre de valeur NULL dans un tableau.


Guillaume.

Hors ligne

#3 20/05/2014 08:32:27

Géronimo
Membre

Re : modification d'une table

Merci gleu pour ta réponse.
J'ai suivi ta recommandation et j'ai fait la modification qui suit :

BEGIN
		IF (pkhexut is NOT NULL) THEN
		 totdiff:=totdiff+1;
		 pkhexut[totdiff]:=pkh;
		 FOREACH pkhtest in ARRAY pkhexut
		 LOOP

Du coup, maintenant il ne m'embête plus avec des valeurs NOT NULL, mais lorsque je teste le "select * from essai()", il ne me met plus de message d'erreur, mais il m'indique juste les noms des colonnes sans mettre aucune valeur de la table...
Comment faire en sorte qu'il m'affiche les lignes correspondantes à la valeur 1000000 de la colonne pkhexut ?

Hors ligne

#4 20/05/2014 12:10:31

Géronimo
Membre

Re : modification d'une table

Aidez-moi, s'il vous plait. Je n'arrive pas à trouver ce que je ne fais pas bien dans mon code.
J'arrive sur deux cas. Pour le premier, j'écris la requête à l'intérieur de la boucle du FOREACH, comme suit :

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 :

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 (vu qu'il y a 90 fois 1000000 dans cette colonne)...


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.
De mon côté, je vais continuer mes tests...

Hors ligne

#5 21/05/2014 12:36:15

Géronimo
Membre

Re : modification d'une table

Personne ne peut donc me répondre ?

C'est pourtant basique comme question... Je veux seulement savoir comment modifier une table par des boucles lorsqu'on est dans le cas d'un RETURNS TABLE (...).

Dernière modification par Géronimo (21/05/2014 12:39:50)

Hors ligne

#6 21/05/2014 15:08:16

Géronimo
Membre

Re : modification d'une table

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 :

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. En tout cas, j'espère que vous serez plus loquaces que vous l'avez été pour ce sujet...


Comment fait-on pour déclarer ce sujet résolu ?


A bientôt !

Hors ligne

#7 21/05/2014 22:17:42

gleu
Administrateur

Re : modification d'une table

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

Pas très étonnant vu que pkhexut vaut toujours NULL dans votre fonction.

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 (vu qu'il y a 90 fois 1000000 dans cette colonne)...

Votre fonction ne fait aucun filtre. Donc, oui, il renvoie toutes les lignes.

En tout cas, j'espère que vous serez plus loquaces que vous l'avez été pour ce sujet...

Ce genre de commentaires est tout à fait inapproprié. Ce forum est une aide gratuite. Vous ne pouvez pas vous attendre à avoir une réponse dans l'heure, ni même dans la journée. Les personnes qui répondent ici le font sur leur temps libre généralement. Ayez au moins la courtoisie de comprendre cela. En tout cas, ce genre de commentaires ne donne absolument pas envie de répondre à vos prochaines questions.


Guillaume.

Hors ligne

#8 22/05/2014 11:05:17

Géronimo
Membre

Re : modification d'une table

gleu,

Je tiens à m'excuser du propos de mon dernier message. J'étais sur le coup de l'émotion, puisque ça faisait depuis 3 ou 4 jours que je cherchais en vain la solution en parcourant des dizaines de forum, tuto et cours. Ça m'a un peu poussé à bout, d'où la réaction très excessive de mon dernier message. J'espère que vous pourrez me pardonner, passer l'éponge et que si j'ai de nouveaux problèmes que je n'arrive pas à résoudre, vous aurez quand même envie de répondre à mes questions.

Bonne journée,

Géronimo.

Dernière modification par Géronimo (22/05/2014 11:49:59)

Hors ligne

Pied de page des forums