Vous n'êtes pas identifié(e).
Bonjour @ tous,
J'ai un problème au niveau de la mise à jour d'une table via un UPDATE en passant par une fonction, je vous explique :
J'ai créé une fonction bidule2() qui s'occupe de faire des update sur la base bd_adresse (ici le champ dom_num est mis à jour en faisant une concaténation du champ domanialite et num_voirie) :
CREATE OR REPLACE FUNCTION bidule2("$1" character varying, "$2" character varying, "$3" character varying, "$4" character varying, "$5" character varying, "$6" integer)
RETURNS integer AS
$BODY$
BEGIN
IF
($4='RD' OR $4='VC' OR $4='A') AND (($4<>'' AND $5<>'')OR($4 IS NOT NULL AND $5 IS NOT NULL))
THEN
RAISE NOTICE 'UPDATE %', 'UPDATE bd_adresse SET dom_num='''||$4||$5||'''WHERE ogc_fid='''||$6||'''';
RETURN 1;
ELSE
RETURN 0;
END IF;
Dans la vue de ma table bd_adresse, j'ai créé une RULE pour effectuer la mise à jour :
CREATE OR REPLACE RULE "_UPDATE" AS
ON UPDATE TO bd_adresse_unique_view DO INSTEAD ( SELECT bidule2(new.nom_type, new.nom_article, new.nom_lib, new.domanialite, new.num_voirie, new.ogc_fid) AS bidule;
UPDATE bd_adresse SET ogc_fid = new.ogc_fid, wkb_geometry = new.wkb_geometry, code_insee = new.code_insee, commune = new.commune, id_troncon_bda = new.id_troncon_bda, id_voie_bda = new.id_voie_bda, id_troncon_diag = new.id_troncon_diag, id_voie_diag = new.id_voie_diag, iddomanialite = new.iddomanialite, domanialite = new.domanialite, nom_type = new.nom_type, nom_article = new.nom_article, nom_lib = new.nom_lib, num_voirie = new.num_voirie, nom_voie = new.nom_voie, dom_num = new.dom_num, nom_num = new.nom_num, nom_detaille = new.nom_detaille, nom_detaille_dom_num = new.nom_detaille_dom_num, long_carto_troncon = new.long_carto_troncon, long_carto_voie_bda = new.long_carto_voie_bda, modif_adresse = new.modif_adresse, nb_troncon_bda = new.nb_troncon_bda
WHERE bd_adresse.ogc_fid = old.ogc_fid;
);
Pourtant, lorsque je fais un UPDATE sur ma vue :
UPDATE bd_adresse_unique_view SET num_voirie='30' WHERE ogc_fid='7659'
Ni ma vue, ni ma table source ne se met à jour, hormis num_voirie, alors que le résultat de mon RAISE NOTICE semble plutôt positif :
NOTICE: UPDATE UPDATE bd_adresse_unique_view SET dom_num='RD30'WHERE ogc_fid='7659'
Donc le problème que j'ai ici est : la répercution des résultats de ma fonction dans ma table via une vue.
Merci.
Bonjour,
J'ai suivi les conseils à rjuju. J'ai donc créé une vue de ma table unique et je tente de réaliser mes mises à jours directement sur cette vue. Visiblement un autre problème se pose, par rapport àla mise à jour d'une table à l'aide d'une focntion (je le met dans un nouveau post).
Merci.
Bonjour rjuju,
Oui c'est ce que je me suis dit, je pourrais socker les voies dans une table et les troncons dans une autre avec une clé étrangére pour faire le lien, mais j'avoue que cette idée ne me séduit pas vraiment...
Bonjour Gleu,
c'est exactement ça le problème, vous avez très bien cerné le problème.
Bonjour @ tous,
je vous explique mon prôblème :
J'ai une table concernant le réseau routier avec un ogc_fid, id_voie, long_carto_troncon, long_carto_voie.
Je souhaiterais pour une modification de l'id_voie re-calculer automatiquement toutes les longueurs de voie et les mettre à jour. Cela signifie donc qu'il va falloir mettre à jour la nouvelle longueur de voie, et la longueur de l'ancienne voie.
Pour atteindre cet objectif, j'ai fait un trigger avec une boucle dont la partie qui nous concerne est la suivante (ici l'exemple ne concerne que la MAJ de la nouvelle voie) :
FOR champ3 IN SELECT ogc_fid,(SUM(long_carto_troncon)+NEW.long_carto_troncon)AS long_totale_voie FROM bd_adresse WHERE id_voie_bda=NEW.id_voie_bda GROUP BY ogc_fid
LOOP
NEW.long_carto_voie_bda:=champ3.long_totale_voie;
END LOOP;
Et en fait, rien ne se met à jour hormis la ligne concernée par le changement de champ (c'est à dire que si je modifie l'id_voie de la ligne 32, seul la longueur de voie de cette ligne change).
Je ne peut pas faire un 'UPDATE table SET (...) puisque mon trigger se déclench sur un BEFORE INSERT OR UPDATE.
Pour information la version de psotgres que j'ai est "PostgreSQL 8.3.10, compiled by Visual C++ build 1400" je ne peut donc pas utiliser de curseur.
si vous avez des solutions ou des pistes je suis preneur.
Merci d'avance.
Geo-x
Oui Gleu vous avez tout à fait raison.
Je vous avais donné une mauvaise information avant que ne me donniez la fameuse requête :
SELECT version()
qui elle me répond :
"PostgreSQL 8.3.10, compiled by Visual C++ build 1400"
Pour info, vos réponses à ce sujet m'ont permis d'effectuer un certains nombres de manipulations de données supplémentaires.
Donc encore merci.
Geo-x
Bonjour,
tout d'abord, je ne connaissais pas la requête :
select version()
Donc merci, il s'agit d'une version en 1.8.3.
Ensuite, il est vrai que si j'enlève le curseur ça fonctionne à merveille ! Un grand merci à vous deux pour votre rapidité et disponibilité (comme à chaque fois et ce n'est pas sur tous les forums pareils).
Très bonne journée à vous, pour moi, elle commence pas mal ;-)
Geo-x
Je vous remercie à tous les deux pour votre aide toujours aussi rapide et efficace.
Malheureusement il semblerait que ma version de postgres (1.8.4 pourtant...) ne permette pas d'utiliser ce genre de requête :
ERROR: syntax error at or near "OVER"
LIGNE 2 : ...LECT a,b,c, row_number() OVER (PART...
********** Erreur **********
ERROR: syntax error at or near "OVER"
État SQL :42601
Caractère : 111
Et là j'avoue que n'utilisant pas ce genre de requête, je vous fais à 100% confiance, mais je ne comprend plus vraiment ce que je fais puisque je ne connais pas la "window function".
Par ailleurs en essayant à nouveau la requête suivante avec mes paramètres :
CREATE OR REPLACE FUNCTION test()
RETURNS integer AS
$BODY$
DECLARE
curseur CURSOR FOR SELECT DISTINCT A,B,C FROM table_a_modif;
matable record;
matable2 record;
compteur integer;
BEGIN
FOR matable IN curseur
LOOP
compteur=1;
FOR matable2 IN SELECT cle_primaire,table_a_modif.A,table_a_modif.B,table_a_modif.C FROM table_a_modif WHERE table_a_modif.matable.A=A AND table_a_modif.B=matable.B AND table_a_modif.C=matable.C
LOOP
UPDATE table_a_modif SET D=compteur WHERE cle_primaire = matable2.cle_primaire;
compteur=compteur+1;
END LOOP;
END LOOP;
return 1;
END;
$BODY$
language plpgsql;
J'ai toujours le message :
ERROR: syntax error at or near "$1"
LIGNE 1 : $1
^
REQUÊTE : $1
CONTEXTE : SQL statement in PL/PgSQL function "test2" near line 7
********** Erreur **********
ERROR: syntax error at or near "$1"
État SQL :42601
Contexte : SQL statement in PL/PgSQL function "test2" near line 7
Alors j'ai bien quelques '' dans ma requête qui suit le 'curseur CURSOR FOR SELECT (...)' mais même si j'enlève tout ça ne focntionne toujours pas. J'ai également essayé de changer tous les noms de variable, rien n'y fait.
J'ai juste l'impression que la requête de ma focntion
FOR matable IN curseur
n'est pas accepté par postgres...
Bonjour Rjuju,
Merci pour votre réponse, j'ai corrigé le compteur=1 mais je ne vois pas trop pourquoi il faudrait mettre un UPDATE dans ma requête ?
Ma table a une clé primaire et des clés étrangéres oui.
Avec le code que je vous ai fourni j'ai le message suivant de postgres :
ERROR: syntax error at or near "$1"
LIGNE 1 : $1
^
REQUÊTE : $1
CONTEXTE : SQL statement in PL/PgSQL function "test2" near line 9
********** Erreur **********
ERROR: syntax error at or near "$1"
État SQL :42601
Contexte : SQL statement in PL/PgSQL function "test2" near line 9
Il semblerait que cela vienne de
FOR table IN curseur
Du coup j'ai testé avec :
OPEN curseur;
FOR table IN curseur
avec un
END LOOP;
CLOSE curseur;
Mais c'est pas mieux...
Par ailleurs pourriez-vous me donner la différence entre un FETCH NEXT FROM curseur et un MOVE NEXT FROM curseur ?
Merci de votre aide.
Bonjour à tous,
je sollicite à nouveau vos connaissances pour le problème suivant :
J'ai des colonnes A/B/C/D dans une table.
Dans cette table les données ressemblent à celles-là :
a/b/c/-
a/b/c/-
a/b/c/-
d/f/g/-
d/f/g/-
d/f/g/-
Ce que je souhaiterais faire c'est :
1-Je sélectionne distinctement mes différents cas possibles :
a/b/c/-
d/f/g/-
2-Pour chacun de ces cas, je sélectionne toutes les lignes dans la table source, exemple cas1 :
a/b/c/-
a/b/c/-
a/b/c/-
3-Et pour ces lignes sélectionnées, je met dans une colonne D un compteur :
a/b/c/1
a/b/c/2
a/b/c/3
Qui recommence à 0 dans chaque cas:
d/f/g/1
d/f/g/2
d/f/g/3
Pour ce faire, j'ai créé une fonction sous postgres :
CREATE OR REPLACE FUNCTION test()
RETURNS integer AS
$BODY$
DECLARE
curseur CURSOR FOR SELECT DISTINCT A,B,C FROM table_a_modif;
table record;
table2 record;
compteur integer;
BEGIN
compteur=1;
FOR table IN curseur
LOOP
FOR table2 IN SELECT table_a_modif.A,table_a_modif.B,table_a_modif.C FROM table_a_modif,table WHERE table_a_modif.A=table.A,table_a_modif.B=table.B,table_a_modif.C=table.C
LOOP
UPDATE table_a_modif SET D=compteur;
compteur=compteur+1;
END LOOP
FETCH NEXT FROM curseur
END LOOP;
return 1;
END
Mais vu que je ne suis pas familier du curseur (d'ailleurs je ne sais pas s'il est vraiment indispensable de l'utiliser dans ce cas précis) je ne sais pas vraiment comment m'y prendre.
Si vous auriez quelques pistes à me donner sur la direction à prendre, je vous en serais reconnaissant.
Merci beaucoup pour ces précisions Gleu ;-)
Ben alors là...c'est exactement ça!
Merci beaucoup.
Par
On ne peut pas retourner plusieurs résultats d'une fonction
C'est le fait que je voulais retourner de ma fonction deux colonnes distinctes avec deux données différentes. Je pensais que les fonctions ne permettaient de retourner un seul résultat, comme par exemple une fonction sur les caractères retourne le mot en entrée avec les espaces supprimés (je ne sais pas si je suis très clair là...)
Par rapport au "pseudo code" (j'ai bien aimé votre définition) que vous avez transformé en "code" digne de ce nom : j'aurais quelques question pour être sûr de bien comprendre :
1-
(OUT p_table text, OUT p_geometrytype text)
Je n'avais encore jamais vu ce OUT, généralement il y a simplement écrit le type de champ. Donc si je comprend bien, quand en entrée de fonction j'ai besoin d'un champ de type integer et un champ de type text et qu'en retour j'aurais un résultat en varchar vais mettre :
FUNCTION test (integer, text)
DECLARE $1 varchar;
(...)
RETURN $1
2- je ne connaissais pas la fonction quote_ident merci pour l'info
3- Si je comprend bien on met le RETURN NEXT lorsqu'il y a une série d'enregistrement c'est bien cela?
4- Dans quel cas met on RETURNS et dans quel cas met on RETURN ? c'est selon qu'il y ait un ou plusieurs retour j'imagine?
Merci pour ces compléments d’informations qui me permettront d'approfondir mes connaissances.
Bonjour,
merci pour la précision.
J'avoue ne pas être un as de la fonction sous postgres SQL voici ce que j'ai pondu :
CREATE OR REPLACE FUNCTION test("$1" varchar,"$2" varchar)
RETURNS varchar AS
$BODY$
DECLARE
tables record;
resultat record;
BEGIN
FOR tables IN 'SELECT DISTINCT table_name FROM INFORMATION_SCHEMA.COLUMNS WHERE udt_name='geometry' AND column_name='wkb_geometry''LOOP
EXECUTE 'SELECT DISTINCT table_name,geometrytype(wkb_geometry)as geometrytype FROM 'tables.table_name' GROUP BY table_name'
INTO resultat;
END LOOP;
$1=resultat.table_name;
$2=resultat.geometrytype;
return $1,$2;
END;
mais il y a une logique que je ne maitrise pas au niveau des résultats de la fonction. On ne peut pas retourner plusieurs résultats d'une fonction, et en même temps, on ne peut pas retourner de résultat de type record. Donc comment peut-on faire pour retourner à une table donnée, un type de géométrie??
Bonjour @ tous,
Vous êtes prêts pour un nouveau défi que je n'ai (une fois de plus) pas su relever ?
TOP
Le but est de requêter sur toutes les tables d'une BDD, afin de connaître le type de géométrie définit pour chacune d'entre elle.
Si je visualise le résultat que je veux ça serait quelque chose du genre :
Nom_table géométrie
table 1 POLYGON
table 2 MULTILIPOYGON
table 3 LINE
Donc pour ce faire j'ai fait :
1- Je cherche toutes les tables sur lesquelles je veux requêter :
SELECT DISTINCT table_name FROM INFORMATION_SCHEMA.COLUMNS WHERE udt_name='geometry' AND column_name='wkb_geometry'
2- Et c'est là ou je bloque, je veux pour chacune de ces tables les différents type de géométrie :
SELECT DISTINCT foo.table_name,geometrytype (foo.wkb_geometry)
FROM (SELECT DISTINCT table_name FROM INFORMATION_SCHEMA.COLUMNS WHERE udt_name='geometry' AND column_name='wkb_geometry')as foo
GROUP BY table_name;
Donc en fait l'idée serait de faire un FROM toutes les tables IN ma liste de tables, c'est possible ça??
Merci d'avance!
Merci beaucoup rjuju ça faisait un petit bout de temps que je me posais la question pour ces fonctions.
Pour mon problème, la table 1 avait un champ en caractère ça doit être pour ça.
Encore merci!
Bonjour @ tous,
une question me tarode : Ou peut on trouver les fonctions que l'on peut normalement trouver à l'installation de psotgres?
Je dis ça parce que je n'ai pas les fonctions trim(); btrim(), ltrim(), replace() et j'en passe...
Pour information complémentaire je cherche la fonction trim pour supprimer les ( et les " dans un champ mis à jour à partir d'un record :
FOR record IN SELECT champ1 FROM table1
LOOP
INSERT INTO "table2" (nom) VALUES (record);
END LOOP;
Résultat :
("valeur ")
Je vous remercie par avance de l'aide apportée.
Geo-x
@geoetl
Finalement tout le code que vous m'avez donné lors de votre dernier post a finit par me servir sur une toutes autre base et je vous en remercie.
Pour information, il ne faut pas faire EXECUTE avant un insert into dans ce cas là ;-)
Encore merci.
Geo-x
Euh oui en effet, j'avoue ne pas avoir été très clair sur ce coup là...mea culpa. Il s'agit bien d'un INSERT INTO table2...
Donc pour reformuler :
Initialement :
Table1 (LINESTRING) - Champ1 : a,b,c,a,a,b,c,c,c
Ce que je souhaite avoir :
Table2 (MULTILINESTRING) - Champ1 : a,b,c
Et donc le code qui ne fonctionne pas, mais que j'ai écris :
INSERT INTO table2 (wkb_geometry,champ1)
SELECT wkb_geometry,champ1 FROM table1
WHERE table1.wkb_geometry=st_multi(st_union('SELECT table1.wkb_geometry FROM table1 GROUP BY table1.champ1'));
Bonjour à tous,
Tout et dans le titre avec en plus, un regroupement par condition.
Donc pour résumer,
1- j'ai plusieurs linestring dans une table1, avec un champ1 contenant des infos a,b,c,a,a,b,c,c,c par exemple
2- je veux regrouper en une seule multilinestring dans une table2, avec la condition de regroupement selon table1.champ1
Alors j'ai pondu un truc du style :
INSERT INTO table1 (wkb_geometry,champ1)
SELECT wkb_geometry,champ1 FROM table2
WHERE table2.wkb_geometry=st_multi(st_union('SELECT table1.wkb_geometry FROM table1 GROUP BY table1.champ1'));
Mais l'efficacité n'est pas au rendez-vous :-(
Avez-vous une idée de la piste à suivre?
En fait, ce que je me rend compte avec cette manipulation, c'est qu'en effectuant un trigger codé avec BEFORE INSERT, la séquence s'incrémente avant le trigger !
Par conséquent je me pose vraiment la question, de l'ordre dans lesquelles s'exécutent les différentes fonctions appelées.
Mais non vous n'êtes pas lourd, vous êtes aussi têtus que moi, mais avec la sagesse en plus ;-)
Après il est vrai que FLOP, n'est pas un message d'erreur trés répandu,je qualifierais le FLOP de terme générique signifiant qu'il ne s'agit pas là de message d'erreur mais juste d'un non fonctionnement, donc, FLOP!
En tout cas je te remercie pour ta fonction, par contre je vois que tu fais un RETURNS en booléen, si on fait un RETURNS en TRIGGER dans ce cas là, on fait un RETURN NEW ?
En tout cas merci pour votre aide, et vos conseils avisés !
Il n'empêche, dans la mesure ou je souhaiterais lancer une requête de type 'SELECT setval ('table',1054)' dans un trigger,
j'essaie d'utiliser le PERFORM, mais ça n'a pas l'air de fonctionner...
J'ai également essayé le EXECUTE SELECT (...)
mais pas mieux...
Vous savez comment faire?
Merci!
Geo-x
1- Au niveau des trous, ce qui nous pose problème, c'est que les id dépendant des séquences sont utilisés pour créer des identifiants unique et théoriquement, à la suite (puisqu'ils dépendent d'objets géographiques dont nous avons la gestion derrière)
2- Ce que je n'ai pas évoqué, c'est que nous avons eu le cas de séquences ayant des id inférieurs à la valeur maximale de l'id (suite à des INSERT INTO automatiques)
Donc double problème.
Ce que je voulais dire, c'est qu'au vue de notre configuration il n'est que très peu probable d'avoir deux insertions au même moment même si techniquement c'est possible.
Je creuse donc pour trouver ma solution, je vous tiens au courant si je trouve.
Bonjour Marc,
Sur les champs utilisés dans les séquences nous avons eu des "vide" suite à la suppression d'enregistrements par exemple.
Dans le trigger exposé, ce n'est pas BEFORE UPDATE mais BEFORE INSERT que je voulais mettre bien sûr.
Donc je ne vois pas comment il pourrait y avoir plusieurs insertions au même moment.