Vous n'êtes pas identifié(e).
Bonjour Marc,
La réponse est claire.
Merci.
Bonjour,
Je travaille sur une BD 8.4 sous Cent-OS.
Je dois réécrire des Fonctions Oracle en Pl/PgSQL.
Exemple :
FUNCTION Get_Doc(MODE IN VARCHAR2,ERREUR OUT VARCHAR2,DOC OUT VARCHAR2) RETURN NUMBER IS
retour NUMBER:=-1;
BEGIN
IF NOT(Ctrl(MODE,ERREUR,DOC)) THEN
RAISE_APPLICATION_ERROR(-20001,ERREUR);
ELSE
retour:=1;
END IF;
RETURN(retour);
EXCEPTION
WHEN OTHERS THEN
ERREUR:=SQLERRM;
RETURN(retour);
END Get_Doc;
En consultant la Doc, j'ai vu qu'il n'est pas possible d'écrire une Fonction avec des paramètres en OUT et de renvoyer une valeur.
Comment peut-on procéder ?
Merci pour les réponses.
Bonjour,
Je travaille sur une 8.4.2 sous Cent-OS 5.
J'ai créé une table avec la structure suivante :
CREATE TABLE type_action (
id_type_action CHARACTER(3) NOT NULL,
libelle CHARACTER VARYING(30) NOT NULL,
id_type_operation CHARACTER(1) NOT NULL
);
ALTER TABLE geo.type_action OWNER TO postgres;
J'ai saisi des valeurs sur 1, 2 ou 3 caractères dans le champ ID_TYPE_ACTION.
Lorsque je fais un SELECT, je ne reçois jamais les espaces en fin sur les valeurs contenant 1 ou 2 caractères :
select id_type_act,length(id_type_act),'--'||id_type_act||'--' from type_act;
RR, 2, --RR--
P, 1, --P--
QQQ,3, --QQQ--
Ne devrais-je pas obtenir :
RR , 3, --RR --
P ,3, --P --
QQQ,3, --QQQ--
Merci.
Ok merci pour les infos Guillaume.
Bonjour,
J'ai lu quelques articles sur la réplication mais je ne vois pas s'il est possible, comme sous Oracle, d'avoir une "standby" accessible en lecture ?
Quelqu'un peut-il me renseigner ou m'orienter vers plus d'infos ?
Merci.
Bonjour Marc,
Ce n'est pas que je ne veux pas comprendre mais je dois migrer une base Oracle en production.
Les changements de structure ne peuvent pas se faire facilement.
Je vais travailler dans ce sens.
Merci pour votre analyse.
Bonjour Marc,
Le fait d'avoir cette nouvelle colonne dans la table Document ne réglerai pas le problème des Documents qui ne sont pas dans la liste.
Concernant le CASE WHEN, je teste si le dernier caractère est alphanumérique.
Si non Alors je prends la valeur entière de T.Doc
Si oui Alors je prends la valeur de T.doc - le dernier caractère
Ensuite je compare avec la valeur de D.doc - le dernier caractère
La table Document est alimentée grâce à une liste de documents à produire fournie par le client (la lettre de contrôle est ajoutée pendant cette alimentation).
La table Travail est alimentée par la production qui ne connait pas forcément le caractère de contrôle et qui parfois traite des documents qui ne sont pas dans la liste.
Dans la table document, j'ai la liste des documents sur 7 chiffres + 1 lettre de contrôle
Exemple :
1111111A
4444444K
2222222R
6666666C
Alors que dans la table Travail, dans le champ doc, je peux recevoir soit :
- 7 chiffres + 1 lettre de contrôle
- 7 chiffres
- X chiffres
Exemple :
1111111A
4444444K
2222222
6666666
6487
4474
Dans le CASE WHEN, je fais donc :
SI le dernier caractère de T.doc n'est pas une lettre ALORS je cherche T.doc = 7 premiers caractères de D.doc
SINON je cherche 7 premiers caractères de T.doc = 7 premiers caractères de D.doc
Je fais un LEFT OUTER JOIN pour récupérer les lignes de Travail même si le document n'existe pas dans Document.
J'espère être clair.
La vue utilisée est la suivante :
CREATE VIEW Vue_Action AS
SELECT a.id_act1,ss1.libelle AS lib1,a.id_act2,ss2.libelle AS lib2,a.id_act3,ss3.libelle AS lib3,a.id_act4,ss4.libelle AS lib4
FROM action a,ss_action1 ss1,ss_action2 ss2,ss_action3 ss3,ss_action4 ss4
WHERE a.id_type1='G'
AND a.id_type2=1
AND to_char('now'::text::date::timestamp WITH time zone,'YYYYMMDD'::text)<=a.fin_action::text
AND a.id_act1=ss1.id
AND a.id_act2=ss2.id
AND a.id_act3=ss3.id
AND a.id_act4=ss4.id;
La clé primaire sur A est : ALTER TABLE action ADD CONSTRAINT pk_action PRIMARY KEY(id_act1,id_act2,id_act3,id_act4,fin_action);
Il ya a également un index sur travail : CREATE INDEX travail1 ON travail(jour,personne);
Et voici le explain analyze :
Limit (cost=643219.80..643219.81 rows=1 width=367) (actual time=30633.571..30633.572 rows=1 loops=1)
-> Sort (cost=643219.80..643878.07 rows=263307 width=367) (actual time=30633.569..30633.569 rows=1 loops=1)
Sort Key: t.heure
Sort Method: top-N heapsort Memory: 25kB
-> Merge Join (cost=632566.01..641903.27 rows=263307 width=367) (actual time=30633.309..30633.462 rows=43 loops=1)
Merge Cond: ((((((a.id_act1)::text || (a.id_act2)::text) || (a.id_act3)::text) || (a.id_act4)::text)) = ((t.id_action)::text))
-> Sort (cost=1668.72..1680.86 rows=4855 width=132) (actual time=364.533..364.702 rows=726 loops=1)
Sort Key: (((((a.id_act1)::text || (a.id_act2)::text) || (a.id_act3)::text) || (a.id_act4)::text))
Sort Method: quicksort Memory: 4222kB
-> Hash Join (cost=49.88..1371.46 rows=4855 width=132) (actual time=1.566..234.961 rows=14447 loops=1)
Hash Cond: (a.id_act1 = ss1.id)
-> Hash Join (cost=48.29..1303.12 rows=4855 width=120) (actual time=1.500..194.138 rows=14447 loops=1)
Hash Cond: (a.id_act3 = ss3.id)
-> Hash Join (cost=35.57..1223.65 rows=4855 width=107) (actual time=1.115..177.392 rows=14447 loops=1)
Hash Cond: (a.id_act4 = ss4.id)
-> Hash Join (cost=7.42..1128.74 rows=4855 width=91) (actual time=0.299..159.552 rows=14447 loops=1)
Hash Cond: (a.id_act2 = ss2.id)
-> Seq Scan on action a (cost=0.00..1054.56 rows=4855 width=82) (actual time=0.065..132.866 rows=14447 loops=1)
Filter: ((id_type1 = 'G'::bpchar) AND (id_type2 = 1::numeric) AND (to_char((('now'::text)::date)::timestamp with time zone, 'YYYYMMDD'::text) <= (fin_action)::text))
-> Hash (cost=4.41..4.41 rows=241 width=13) (actual time=0.223..0.223 rows=241 loops=1)
-> Seq Scan on ss_action2 ss2 (cost=0.00..4.41 rows=241 width=13) (actual time=0.007..0.091 rows=241 loops=1)
-> Hash (cost=16.40..16.40 rows=940 width=21) (actual time=0.803..0.803 rows=940 loops=1)
-> Seq Scan on ss_action4 ss4 (cost=0.00..16.40 rows=940 width=21) (actual time=0.009..0.347 rows=940 loops=1)
-> Hash (cost=7.32..7.32 rows=432 width=17) (actual time=0.374..0.374 rows=432 loops=1)
-> Seq Scan on ss_action3 ss3 (cost=0.00..7.32 rows=432 width=17) (actual time=0.008..0.172 rows=432 loops=1)
-> Hash (cost=1.26..1.26 rows=26 width=16) (actual time=0.046..0.046 rows=26 loops=1)
-> Seq Scan on ss_action1 ss1 (cost=0.00..1.26 rows=26 width=16) (actual time=0.014..0.031 rows=26 loops=1)
-> Sort (cost=630897.29..630924.41 rows=10847 width=235) (actual time=30268.120..30268.133 rows=43 loops=1)
Sort Key: ((t.id_action)::text)
Sort Method: quicksort Memory: 31kB
-> Nested Loop Left Join (cost=965.91..630170.27 rows=10847 width=235) (actual time=768.841..30267.651 rows=43 loops=1)
Join Filter: (CASE WHEN (lastalpha(t.doc) = 0::numeric) THEN (t.doc)::text ELSE substr((t.doc)::text, 1, (length((t.doc)::text) - 1)) END = substr((d.doc)::text, 1, (length((d.doc)::text) - 1)))
-> Index Scan using travail1 on travail t (cost=0.01..66.19 rows=62 width=219) (actual time=0.068..0.420 rows=43 loops=1)
Index Cond: ((jour = (('now'::text)::date - 1)) AND (personne = '0000123'::bpchar))
-> Materialize (cost=965.90..1315.81 rows=34991 width=25) (actual time=0.001..13.739 rows=34991 loops=43)
-> Seq Scan on document d (cost=0.00..930.91 rows=34991 width=25) (actual time=0.010..31.729 rows=34991 loops=1)
Total runtime: 30636.099 ms
(37 rows)
Merci pour votre aide Marc.
Bonjour Marc,
En fait je travaille à la migration d'un système basé sur une BD Oracle vers PostgreSQL.
En Oracle, cela fonctionne trés bien avec des temps de réponse trés acceptables et sur des volumes beaucoup plus importants surtout sur la table travail.
Pourquoi dites-vous "il n'y a pas jointure au sens relationnel" ?
je cherche l'égalité entre le champ T.doc de la table travail et le champ D.doc de la table document.
Idem pour le champ T.id_action qui doit avoir une correspondance dans la table Action en concaténant les champs A.id_act1||A.id_act2||A.id_act3||A.id_act4
Bonjour,
Je travaille sur une BD 8.4.2 sous Cent-OS 5.2.
J'ai une requête qui est trés lente alors que le volume de données dans ma base est ridicule.
La requête doit me retourner la dernière ligne de travail de la personne '0000123' pour la veille.
Voilà la requête :
SELECT T.*,A.*,D.libelle
FROM Travail T LEFT OUTER JOIN Document D ON (CASE WHEN LastAlpha(T.doc)=0 THEN T.doc ELSE SUBSTR(T.doc,1,LENGTH(T.doc)-1) END)=SUBSTR(D.doc,1,LENGTH(D.doc)-1),Vue_Action A
WHERE T.jour=CURRENT_DATE-1
AND T.personne='0000123'
AND T.id_action=A.id_act1||A.id_act2||A.id_act3||A.id_act4
ORDER BY T.jour DESC,T.heure DESC LIMIT 1;
Je fais une jointure entre travail et action pour récupérer les paramètres liés à une action.
Je fais une jointure entre travail et document pour récupérer le libelle du document
Le volume des tables est :
travail : 82591 enregistrements
action : 20325 enregistrements
document : 34991 enregistrements
J'ai fait un explain mais je ne sais pas l'exploiter :
Limit (cost=632614.91..632614.92 rows=1 width=367)
-> Sort (cost=632614.91..632620.69 rows=2309 width=367)
Sort Key: t.heure
-> Hash Join (cost=2102.89..632603.37 rows=2309 width=367)
Hash Cond: (a.id_act1 = ss1.id)
-> Hash Join (cost=2101.30..632570.04 rows=2309 width=355)
Hash Cond: (a.id_act2 = ss2.id)
-> Hash Join (cost=2093.88..632530.86 rows=2309 width=346)
Hash Cond: (a.id_act3 = ss3.id)
-> Nested Loop (cost=2081.16..632486.40 rows=2309 width=333)
-> Hash Join (cost=2081.16..631828.23 rows=2309 width=317)
Hash Cond: ((t.id_action)::text = ((((a.id_act1)::text || (a.id_act2)::text) || (a.id_act3)::text)|| (a.id_act4)::text))
-> Nested Loop Left Join (cost=965.91..630170.27 rows=95 width=235)
Join Filter: (CASE WHEN (lastalpha(t.doc) = 0::numeric) THEN (t.doc)::text ELSE substr((t.doc)::text, 1, (length((t.doc)::text) - 1)) END = substr((d.doc)::text, 1, (length((d.doc)::text) - 1)))
-> Index Scan using travail1 on travail t (cost=0.01..66.19 rows=62 width=219)
Index Cond: ((jour = (('now'::text)::date - 1)) AND (personne = '0000781'::bpchar))
-> Materialize (cost=965.90..1315.81 rows=34991 width=25)
-> Seq Scan on document d (cost=0.00..930.91 rows=34991 width=25)
-> Hash (cost=1054.56..1054.56 rows=4855 width=82)
-> Seq Scan on action a (cost=0.00..1054.56 rows=4855 width=82)
Filter: ((id_type1 = 'G'::bpchar) AND (id_type2 = 1::numeric) AND (to_char((('now'::text
)::date)::timestamp with time zone, 'YYYYMMDD'::text) <= (fin_action)::text))
-> Index Scan using pk_ss_action4 on ss_action4 ss4 (cost=0.00..0.27 rows=1 width=21)
Index Cond: (ss4.id = a.id_act4)
-> Hash (cost=7.32..7.32 rows=432 width=17)
-> Seq Scan on ss_action3 ss3 (cost=0.00..7.32 rows=432 width=17)
-> Hash (cost=4.41..4.41 rows=241 width=13)
-> Seq Scan on ss_action2 ss2 (cost=0.00..4.41 rows=241 width=13)
-> Hash (cost=1.26..1.26 rows=26 width=16)
-> Seq Scan on ss_action1 ss1 (cost=0.00..1.26 rows=26 width=16)
(29 rows)
J'espère fournir suffisamment d'éléments.
Pouvez-vous m'aider ?
Merci messieurs pour votre rapidité et les explications claires.
Bonjour Marc,
J'ai fait le pg_ctl -m immediate stop, puis redémarrer le serveur. Tout va bien. Merci.
Faut-il s'inquiter ? étes-vous sûr qu'en aucun cas il n'y a de perte de données ? y-a-t'il un Bug ? la version 8.4.2 ?
Merci pour votre réponse.
Bonjour,
Je travaille sur une version 8.4.2 sous Cent-OS 5.2.
Je viens de lancer la commande : pg_ctl stop et ............. failed
pg_ctl: server does not shut down
Dans le fichier de log, j'ai ces lignes :
2623 2010-03-04 10:16:25 CET 2 LOG: received smart shutdown request
2629 2010-03-04 10:16:25 CET 2 LOG: autovacuum launcher shutting down
[local] 23938 2010-03-04 10:28:21 CET /usr/local/pgsql/bin/postmaster 1 FATAL: the database system is shutting down
[local] 23943 2010-03-04 10:28:48 CET /usr/local/pgsql/bin/postmaster 1 FATAL: the database system is shutting down
J'essaye de me connecter : psql template1 : psql: FATAL: the database system is shutting down
Je fais un pg_ctl status : pg_ctl: server is running (PID: 2623)
Quelqu'un à t'il déjà rencontré ce problème ?
Que faut-il faire ?
Merci pour vos réponses.
Si cela peut aider d'autres personnes :
function test_refcursor()
{
pg_query("begin");
$res1 = pg_query("SELECT fcurs()");
if ($res1!==false) {
list($cname) = pg_fetch_array($res1);
$res2 = pg_query("FETCH ALL IN \"" . $cname . "\"");
if ($res2!==false) {
$all = pg_fetch_all($res2);
print_r($all);
}
}
pg_query("commit");
}
Solution proposée par Estofilo sur Developpez.com
Désolé Guillaume, mais il semble que le tableau soit vide.
Voici les lignes de PHP :
$result1 = pg_query($_query);
$arr1 = pg_fetch_array($result1,NULL,PGSQL_ASSOC);
$tmp = array_keys($arr1);
$result2 = pg_query("FETCH ALL IN ".$tmp[0]);
$arr2 = pg_fetch_array($result2,NULL,PGSQL_ASSOC);
voici ce qui s'affiche :
Warning: pg_query() [function.pg-query]: Query failed: ERROR: cursor "data" does not exist in /usr/local/apache....
Warning: pg_fetch_array() expects parameter 1 to be resource, boolean given in /usr/local/apache....
J'ai ajouté : print_r("--".$_query."--"); pour voir la query, et j'obtiens cela :
--select User.Clients() as data --
Peux-tu m'aider ?
Guillaume,
J'ai bien compris le principe PostgreSQL.
Par contre côté PHP, cela veut-il dire que $result = pg_query($_query); me retourne le nom du curseur ?
Et que je dois faire un nouveau query : $result2 = pg_query("FETCH ALL IN ".$result); ?
Avant de faire la boucle : while ($arr = pg_fetch_array($result2,NULL,PGSQL_ASSOC)) ?
Je ne connais vraiment pas PHP et n'est pas trouvé d'exemple.
Merci pour les solutions.
Bonjour Guillaume,
En fait, je dois reprendre une interface écrite en PHP.
Cette interface communiquait avec une BD Oracle.
Je dois l'adapter pour communiquer avec PostgreSQL.
J'ai des fonctions Oracle qui renvoient des SYS_REFCURSOR.
J'ai réécrit pour renvoyer des REFCURSOR.
Je dois maintenant les exploiter dans le PHP.
Y-a-t'il une solution ?
Merci pour ton aide.
Bonjour à tous,
Je travaille sous Cent-OS 5.2, PostgreSQL 8.4.2.
Je souhaite récupérer un REFCURSOR dans un tableau sous PHP (grand débutant PHP).
J'ai écrit une Fonction Postgres qui retourne un REFCURSOR.
CREATE OR REPLACE FUNCTION USER.Clients() RETURNS REFCURSOR AS '
DECLARE
RClient REFCURSOR;
BEGIN
OPEN RClient FOR
SELECT C.id_client,C.libelle
FROM USER.Client C;
RETURN RClient;
END;
' LANGUAGE 'plpgsql';
J'ai utilisé PG_FETCH_ARRAY sous PHP (comme dans la Doc : http://www.php.net/manual/fr/function.p … array.php).
J'essaye d'afficher les valeurs mais je n'obtiens rien.
public function db_ref_cursor($_query)
{
$aRetTab = array();
$result = pg_query($_query);
while ($arr = pg_fetch_array($result,NULL,PGSQL_ASSOC))
{
echo $arr["libelle"].' <br/> <br/>';
}
pg_free_result($result);
return $aRetTab;
}
Quelqu'un à t'il déjà utilisé un REFCURSOR sous PHP ?
Pouvez-vous m'aider à construire mon tableau à partir de ce REFCURSOR ?
Merci pour les réponses.
J'ai bien lu la Doc mais en fait j'étais parti à fond sous PgAdmin.
Merci encore Guillaume.
Bonjour,
Effectivement, peut-être en détaillant mon problème ce sera plus clair.
J'ai un développeur PHP qui me demande une fonction Pl/PgSQL.
Cette fonction doit :
- Retourner une liste de N derniers clients,
- Prendre en entrée un Curseur et un Entier(N),
- Retourner le Curseur.
J'ai créé la fonction :
CREATE OR REPLACE FUNCTION DernieresLignes(REFCURSOR,NUMERIC) RETURNS REFCURSOR AS '
DECLARE
BEGIN
OPEN $1 FOR
SELECT C.*
FROM Client C
ORDER BY C.id_client DESC LIMIT TO_NUMBER($2);
RETURN $1;
END;
' LANGUAGE 'plpgsql';
Pour vérifier que ma fonction marche et avant de la founir au développeur, je souhaite visualiser le résultat de la fonction (sous psql ou PgAdmin).
Comment faire ?
Merci pour votre aide.
Bonjour à tous,
Je travaille avec PostgreSQL 8.4.2 sous CentOS 5.2.
Je voudrais afficher le résultat d'une fonction qui retourne un REFCURSOR sous psql ou PgAdmin.
Avez-vous une solution ?
Merci pour vos réponses.
Bonjour à tous,
Je travaille actuellement sur la mise en place d'un Serveur PostgreSQL 8.4.2 sur CentOS 5.2.
Je m'intérogge sur l'utilité de définir des tablespaces sur une machine qui ne contient qu'un disque. Même question sur les tablespaces temporaires. Le default tablespace est-il suffisant ?
Avez-vous des avis, des infos à me donner ?
Merci pour les réponses.
Bonjour Guillaume,
J'ai arrêté et redémarré PostgreSQL aprés que la machine soit complétement démarrée.
Les 2 services stats_buffer et stats_collector sont démarrés.
C'est donc bien qu'il y a un problème avec le réseau.
J'ai demandé à l'équipe système de modifier l'ordre des démarrage des différents services.
A présent tout fonctionne bien.
Désolé pour le temps perdu.
Merci encore.