IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PL/SQL Oracle Discussion :

PL/SQL, PHP et Tableaux


Sujet :

PL/SQL Oracle

  1. #1
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    171
    Détails du profil
    Informations personnelles :
    Âge : 55

    Informations forums :
    Inscription : Juin 2008
    Messages : 171
    Points : 65
    Points
    65
    Par défaut PL/SQL, PHP et Tableaux
    Bonjour,

    Je souhaite créer un package avec une fonction qui :
    - alimente certaines colonnes d'un tableau avec le résultat d'un curseur,
    - alimente les autres colonnes avec des valeurs calculées.

    Puis je veux que cette fonction retourne le tableau qui sera exploité dans un soft en PHP.

    Quelle technique utiliser ? Quelqu'un peut-il m'aiguiller ?

    Merci.

  2. #2
    Expert éminent sénior Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Points : 11 252
    Points
    11 252
    Par défaut
    Function pipelined
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Select *
      From table(procedure(cursor('Select * From t')));
    où la procedure fait ce que t'as besoin.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    500
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2007
    Messages : 500
    Points : 639
    Points
    639
    Des chercheurs qui cherchent, on en trouve, mais des chercheurs qui trouvent, on en cherche !

  4. #4
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    171
    Détails du profil
    Informations personnelles :
    Âge : 55

    Informations forums :
    Inscription : Juin 2008
    Messages : 171
    Points : 65
    Points
    65
    Par défaut PL/SQL, PHP et Tableaux
    Bonjour et merci pour vos réponses.

    J'ai testé la méthode de la collection :

    Déclaration de ma collection
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    create or replace type tTabHisto is table of varchar2(10000);
    Création d'un package avec cette Fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    FUNCTION HistoDetail() RETURN tTabHisto IS
        tTableau tTabHisto;
        nInd INTEGER;
        CURSOR CPointage IS
            SELECT ....
            FROM ....;
        RPointage CPointage%ROWTYPE;
    BEGIN
        tTableau:=tTabHisto();
        OPEN CPointage;
        LOOP
            tTableau.EXTEND;
            FETCH CPointage INTO RPointage;
            EXIT WHEN CPointage%NOTFOUND;
            tTableau(nInd):=RPointage....||';'||RPointage....;
            nInd:=nInd+1;
        END LOOP;
        CLOSE CPointage;
        RETURN tTableau;
    END HistoDetail;
    Le développeur PHP me dit qu'il obtient l'erreur suivante lorsqu'il appel ma fonction : "oci_fetch_assoc: ORA-00932: inconsistent datatypes: expected CHAR got TABLE".

    Avez-vous une idée ?

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    500
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2007
    Messages : 500
    Points : 639
    Points
    639
    Par défaut
    Ta fonction retourne la variable tTabHisto de type tableau (TABLE dans le message d'erreur), et je suppose que côté PHP tu la balances dans une variable simple de type chaîne de caractères (CHAR)... Il faudrait que le réceptacle côté PHP soit également de type tableau.
    Des chercheurs qui cherchent, on en trouve, mais des chercheurs qui trouvent, on en cherche !

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    178
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 178
    Points : 220
    Points
    220
    Par défaut
    Attention !

    Cette méthode est très gourmande en mémoire côté serveur car tous les résultats sont agglomérés dans un tableau avant de les envoyer tous ensemble au client (PHP ici). Si le nombre d'enregistrements est important (et d'autant plus si les champs sont nombreux et/ou volumineux, ce qui semble être le cas puisque tu prévois 10000 octets max par enregistrement), cette solution n'est pas adaptée.

    De plus, tous les champs sont transformés en string puis concaténés... On perd donc les noms des colonnes ainsi que leur type au niveau de PHP.

    Le plus approprié à mon sens est simplement d'écrire le SELECT adéquat dans lequel on prend les colonnes non calculés et on ajoute les colonnes calculées, puis on ouvre un curseur (ref cursor plus exactement) sur ce SELECT et on le retourne. De ce fait, la page PHP lira simplement le curseur renvoyé par la procédure (ou plutôt fonction dans ce cas) comme le résultat d'un SELECT standard.

    Si tu nous donnes plus de détails sur la requête, nul doute que l'on pourra t'aider à la construire .

    rbaraer

  7. #7
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    171
    Détails du profil
    Informations personnelles :
    Âge : 55

    Informations forums :
    Inscription : Juin 2008
    Messages : 171
    Points : 65
    Points
    65
    Par défaut PL/SQL, PHP et Tableaux
    Bonjour et merci pour les réponses,
    La solution de retourner un refcursor serait donc possible ?
    Alors voilà le contenu complet de ma fonction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
     
    FUNCTION HistoDetail(cIdPerso CHAR,cIdPersoCgu VARCHAR2,cJDeb CHAR,cJFin CHAR,cFinActivite CHAR) RETURN tTabHisto IS
    	tTableau tTabHisto;
    	nInd INTEGER;
    	cJFinPtgPers CHAR(8);
    	cHeureFin CHAR(6);
    	cLigne VARCHAR2(300);
    	CURSOR CPointage IS
    		SELECT TO_CHAR(POIN.jour,'YYYYMMDD') CJour,POIN.heure CHeureDeb,'000000' CHeureFin,'000000' CTemps,A.id_ligne CIdLig,L.libelle CLibLig,A.id_plan CIdPlan,P.libelle CLibPlan,A.id_fonction CIdFonc,F.libelle CLibFonc,A.id_operation CIdOpe,O.libelle CLibOpe,POIN.of_sec COfSec,OO.libelle ClibOf
    		FROM Pointage POIN LEFT OUTER JOIN O_f OO ON (DECODE(oth_pack.LASTALPHA(POIN.of_sec),0,POIN.of_sec,SUBSTR(POIN.of_sec,1,LENGTH(POIN.of_sec)-1))=SUBSTR(OO.of_sec,1,LENGTH(OO.of_sec)-1)),Activite A,Ligne L,Plan P,Fonction F,Operation O
    		WHERE POIN.jour=TRUNC(SYSDATE)
    		AND POIN.id_perso=cIdPerso
    		AND POIN.id_activite=A.id_ligne||A.id_plan||A.id_fonction||A.id_operation
    		AND A.id_type_ptg_sst='G'
    		AND TO_CHAR(SYSDATE,'YYYYMMDD')<=TO_CHAR(A.date_fin_valide,'YYYYMMDD')
    		AND A.id_ligne=L.id_ligne AND A.id_plan=P.id_plan AND A.id_fonction=F.id_fonction AND A.id_operation=O.id_operation
    		ORDER BY POIN.jour,POIN.heure DESC,POIN.id DESC;
    	RPointage CPointage%ROWTYPE;
    	CURSOR CPtgPers IS
    		SELECT TO_CHAR(PTG.jour,'YYYYMMDD') CJour,PTG.heure_deb CHeureDeb,PTG.heure_fin CHeureFin,Tps_pack.Centi2Heure(PTG.Temps) CTemps,A.id_ligne CIdLig,L.libelle CLibLig,A.id_plan CIdPlan,P.libelle CLibPlan,A.id_fonction CIdFonc,F.libelle CLibFonc,A.id_operation CIdOpe,O.libelle CLibOpe,PTG.ofs_cpt COfSec,OO.libelle CLibOf
    		FROM Ptg_pers PTG,Activite A,Ligne L,Plan P,Fonction F,Operation O,O_f OO
    		WHERE PTG.jour>=TO_DATE(cJDeb,'YYYYMMDD') AND PTG.jour<=TO_DATE(cJFinPtgPers,'YYYYMMDD')
    		AND PTG.id_perso=cIdPersoCgu
    		AND PTG.id_ligne=A.id_ligne AND PTG.id_plan=A.id_plan AND PTG.id_fonction=A.id_fonction AND PTG.id_operation=A.id_operation
    		AND A.id_type_ptg_sst='G'
    		AND cJDeb<=TO_CHAR(A.date_fin_valide,'YYYYMMDD')
    		AND A.id_ligne=L.id_ligne AND A.id_plan=P.id_plan AND A.id_fonction=F.id_fonction AND A.id_operation=O.id_operation
    		AND PTG.ofs_cpt=OO.of_sec(+)
    		ORDER BY PTG.jour DESC,PTG.heure_deb DESC,PTG.heure_fin DESC;
    	RPtgPers CPtgPers%ROWTYPE;
    	Invalid_HistoDetail EXCEPTION;
    BEGIN
    	tTableau:=tTabHisto();
    	nInd:=1;
    	IF cJFin >= TO_CHAR(SYSDATE,'YYYYMMDD') THEN cJFinPtgPers:=TO_CHAR(SYSDATE-1,'YYYYMMDD');ELSE cJFinPtgPers:=cJFin;END IF;
    	IF cJFinPtgPers != cJFin THEN
    		cHeureFin:=TO_CHAR(SYSDATE,'HH24MISS');
    		OPEN CPointage;
    		LOOP
    			tTableau.EXTEND;
    			FETCH CPointage INTO RPointage;
    			EXIT WHEN CPointage%NOTFOUND;
    			cLigne:=RPointage.CJour||';'||RPointage.CHeureDeb||';';
    			IF nInd = 1 THEN
    				IF RPointage.CIdOpe = cFinActivite THEN
    					cHeureFin:=RPointage.CHeureDeb;tTableau.TRIM;nInd:=0;
    				ELSE
    					cLigne:=cLigne||cHeureFin||';'||Tps_pack.HeureDiff(RPointage.CHeureDeb,cHeureFin,0)||';';
    					cHeureFin:=RPointage.CHeureDeb;
    				END IF;
    			ELSE
    				IF RPointage.CIdOpe = cFinActivite THEN
    					cHeureFin:=RPointage.CHeureDeb;tTableau.TRIM;nInd:=nInd-1;
    				ELSE
    					cLigne:=cLigne||cHeureFin||';'||Tps_pack.HeureDiff(RPointage.CHeureDeb,cHeureFin,0)||';';
    					cHeureFin:=RPointage.CHeureDeb;
    				END IF;
    			END IF;
    			cLigne:=cLigne||RPointage.CIdLig||';'||RPointage.CLibLig||';'||RPointage.CIdPlan||';'||RPointage.CLibPlan||';'||RPointage.CIdFonc||';'||RPointage.CLibFonc||';'||RPointage.CIdOpe||';'||RPointage.CLibOpe||';'||RPointage.COfSec||';'||RPointage.CLibOf;
    			tTableau(nInd):=cLigne;
    			nInd:=nInd+1;
    		END LOOP;
    		CLOSE CPointage;
    		tTableau.TRIM;
    	END IF;
    	OPEN CPtgPers;
    	LOOP
    		tTableau.EXTEND;
    		FETCH CPtgPers INTO RPtgPers;
    		EXIT WHEN CPtgPers%NOTFOUND;
    		cLigne:=RPtgPers.CJour||';'||RPtgPers.CHeureDeb||';'||RPtgPers.CHeureFin||';'||RPtgPers.CTemps||';'||RPtgPers.CIdLig||';'||RPtgPers.CLibLig||';'||RPtgPers.CIdPlan||';'||RPtgPers.CLibPlan||';'||RPtgPers.CIdFonc||';'||RPtgPers.CLibFonc||';'||RPtgPers.CIdOpe||';'||RPtgPers.CLibOpe||';'||RPtgPers.COfSec||';'||RPtgPers.CLibOf;
    		tTableau(nInd):=cLigne;
    		nInd:=nInd+1;
    	END LOOP;
    	CLOSE CPtgPers;
    	tTableau.TRIM;
    	RETURN tTableau;
    EXCEPTION
    	WHEN OTHERS THEN
    		RAISE Invalid_HistoDetail;
    END HistoDetail;
    Pour expliquer un peu, j'ai 2 curseur :
    CPointage qui contient des heures de début d'activité
    CPtgPers qui contient des heures de début et fin d'activité
    Je souhaite retourner, à PHP, la liste des enregistrements (répondant à certains critères) avec heures de début et fin.
    J'espère être clair et encore merci pour votre aide.

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    178
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 178
    Points : 220
    Points
    220
    Par défaut
    OK. Le principe serait à peu près ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    FUNCTION HistoDetail(
        cIdPerso CHAR,
        cIdPersoCgu VARCHAR2,
        cJDeb CHAR,
        cJFin CHAR,
        cFinActivite CHAR) RETURN SYS_REFCURSOR IS
     
        rc SYS_REFCURSOR;
        cJFinPtgPers CHAR(8);
        cHeureFin CHAR(6);
        Invalid_HistoDetail EXCEPTION;
     
    BEGIN
     
        IF (cJFin >= TO_CHAR(SYSDATE,'YYYYMMDD')) THEN 
            cJFinPtgPers:=TO_CHAR(SYSDATE-1,'YYYYMMDD');
        ELSE 
            cJFinPtgPers:=cJFin;
        END IF;
     
        IF (cJFinPtgPers != cJFin) THEN
            cHeureFin:=TO_CHAR(SYSDATE,'HH24MISS');
        END IF;
     
        OPEN rc FOR
            SELECT TO_CHAR(POIN.jour,'YYYYMMDD') CJour,
                POIN.heure CHeureDeb,
                '000000' CHeureFin,
                '000000' CTemps,
                A.id_ligne CIdLig,
                L.libelle CLibLig,
                A.id_plan CIdPlan,
                P.libelle CLibPlan,
                A.id_fonction CIdFonc,
                F.libelle CLibFonc,
                A.id_operation CIdOpe,
                O.libelle CLibOpe,
                POIN.of_sec COfSec,
                OO.libelle ClibOf
            FROM Pointage POIN LEFT OUTER JOIN O_f OO ON (DECODE(oth_pack.LASTALPHA(POIN.of_sec),0,POIN.of_sec,SUBSTR(POIN.of_sec,1,LENGTH(POIN.of_sec)-1))=SUBSTR(OO.of_sec,1,LENGTH(OO.of_sec)-1)),Activite A,Ligne L,Plan P,Fonction F,Operation O
            WHERE POIN.jour=TRUNC(SYSDATE)
            AND POIN.id_perso=cIdPerso
            AND POIN.id_activite=A.id_ligne||A.id_plan||A.id_fonction||A.id_operation
            AND A.id_type_ptg_sst='G'
            AND TO_CHAR(SYSDATE,'YYYYMMDD')<=TO_CHAR(A.date_fin_valide,'YYYYMMDD')
            AND A.id_ligne=L.id_ligne AND A.id_plan=P.id_plan AND A.id_fonction=F.id_fonction AND A.id_operation=O.id_operation
            AND (cJFinPtgPers != cJFin) -- CPointage n'était ouvert que sous cette condition
            ORDER BY POIN.jour,POIN.heure DESC,POIN.id DESC
            UNION ALL
            SELECT TO_CHAR(PTG.jour,'YYYYMMDD') CJour,
                PTG.heure_deb CHeureDeb,
                PTG.heure_fin CHeureFin,
                Tps_pack.Centi2Heure(PTG.Temps) CTemps,
                A.id_ligne CIdLig,
                L.libelle CLibLig,
                A.id_plan CIdPlan,
                P.libelle CLibPlan,
                A.id_fonction CIdFonc,
                F.libelle CLibFonc,
                A.id_operation CIdOpe,
                O.libelle CLibOpe,
                PTG.ofs_cpt COfSec,
                OO.libelle CLibOf
            FROM Ptg_pers PTG,Activite A,Ligne L,Plan P,Fonction F,Operation O,O_f OO
            WHERE PTG.jour>=TO_DATE(cJDeb,'YYYYMMDD') AND PTG.jour<=TO_DATE(cJFinPtgPers,'YYYYMMDD')
            AND PTG.id_perso=cIdPersoCgu
            AND PTG.id_ligne=A.id_ligne AND PTG.id_plan=A.id_plan AND PTG.id_fonction=A.id_fonction AND PTG.id_operation=A.id_operation
            AND A.id_type_ptg_sst='G'
            AND cJDeb<=TO_CHAR(A.date_fin_valide,'YYYYMMDD')
            AND A.id_ligne=L.id_ligne AND A.id_plan=P.id_plan AND A.id_fonction=F.id_fonction AND A.id_operation=O.id_operation
            AND PTG.ofs_cpt=OO.of_sec(+)
            ORDER BY PTG.jour DESC,PTG.heure_deb DESC,PTG.heure_fin DESC;
     
        RETURN rc;
     
    EXCEPTION
        WHEN OTHERS THEN
            RAISE Invalid_HistoDetail;
     
    END HistoDetail;
    Reste à adapter les calculs de CHeureFin et CTemps du premier SELECT.

    Pour cela, peux-tu fournir un exemple d'enregistrements et le principe du calcul ?

  9. #9
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    171
    Détails du profil
    Informations personnelles :
    Âge : 55

    Informations forums :
    Inscription : Juin 2008
    Messages : 171
    Points : 65
    Points
    65
    Par défaut PL/SQL, PHP et Tableaux
    Rbaraer,

    Des lignes du curseur CPointage :
    Jour;Debut;Fin;Temps;Id_lig;Lib_lig;Id_plan;Lib_plan;Id_fonc;Lib_Fonc;Id_ope;Lib_ope;OF;Lib_of
    20080715;170000;000000;000000;100;BRICOLAGE;110;BOIS;120;EBENISTERIE;0000;FIN ACTIVITE;;
    20080715;140000;000000;000000;100;BRICOLAGE;110;BOIS;120;EBENISTERIE;1300;VERNISSAGE;23456789A;CHAISES DU CURE
    20080715;110000;000000;000000;200;JARDINAGE;210;ESPACES VERTS;220;TONTE;2300;BORDURES;1234567B;JARDIN DU MAIRE
    20080715;070000;000000;000000;200;JARDINAGE;210;ESPACES VERTS;240;DEBROUSSAILLAGE;2410;ARBUSTES;1234567B;JARDIN DU MAIRE

    Des lignes du curseur CPtgPers :
    Jour;Debut;Fin;Temps;Id_lig;Lib_lig;Id_plan;Lib_plan;Id_fonc;Lib_Fonc;Id_ope;Lib_ope;OF;Lib_of
    20080714;150000;153000;003000;200;JARDINAGE;210;ESPACES VERTS;240;DEBROUSSAILLAGE;2410;ARBUSTES;1234567B;JARDIN DU MAIRE
    20080714;070000;150000;080000;100;BRICOLAGE;110;BOIS;120;EBENISTERIE;1300;VERNISSAGE;23456789A;CHAISES DU CURE

    Résultat souhaité :
    20080715;140000;170000;030000;100;BRICOLAGE;110;BOIS;120;EBENISTERIE;1300;VERNISSAGE;23456789A;CHAISES DU CURE
    20080715;110000;140000;030000;200;JARDINAGE;210;ESPACES VERTS;220;TONTE;2300;BORDURES;1234567B;JARDIN DU MAIRE
    20080715;070000;110000;040000;200;JARDINAGE;210;ESPACES VERTS;240;DEBROUSSAILLAGE;2410;ARBUSTES;1234567B;JARDIN DU MAIRE
    20080714;150000;153000;003000;200;JARDINAGE;210;ESPACES VERTS;240;DEBROUSSAILLAGE;2410;ARBUSTES;1234567B;JARDIN DU MAIRE
    20080714;070000;150000;080000;100;BRICOLAGE;110;BOIS;120;EBENISTERIE;1300;VERNISSAGE;23456789A;CHAISES DU CURE

    Objectif :
    Retourner les activités d'une période donnée, avec heure de début, heure de fin et temps passé, trié de façon décroissante.

    Infos :
    Les activités du jour sont obtenues avec le curseur CPointage. Il faut faire le chainage des activités et calculer le temps. L'activité courante clôture l'activité précédente. Le midi, en fin de journée ou si la personne doit interrompre sa journée, l'activité '0000;FIN ACTIVITE' sert à clôturer l'activité précédente.
    Les activités des jours antérieurs sont obtenues avec le curseur CPtgPers. Le chainage et le calcul sont déjà fait.

    J'espère être assez clair.

    Bonus : pour compliquer un peu, une deuxième fonction devra fournir le même style de tableau, mais sans les heures de début et fin et regroupées par jour et activité avec cumul du temps.

  10. #10
    Expert éminent sénior Avatar de mnitu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    5 611
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 5 611
    Points : 11 252
    Points
    11 252
    Par défaut
    Et tu ne veux pas regarder les fonctions pipelined ?

  11. #11
    Membre actif
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    178
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 178
    Points : 220
    Points
    220
    Par défaut
    Ceci devrait marcher (peut-être à adapter un peu) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    FUNCTION HistoDetail(
        cIdPerso CHAR,
        cIdPersoCgu VARCHAR2,
        cJDeb CHAR,
        cJFin CHAR,
        cFinActivite CHAR) RETURN SYS_REFCURSOR IS
        
        rc SYS_REFCURSOR;
        cJFinPtgPers CHAR(8);
        cHeureFin CHAR(6);
        Invalid_HistoDetail EXCEPTION;
        
    BEGIN
    
        IF (cJFin >= TO_CHAR(SYSDATE,'YYYYMMDD')) THEN 
            cJFinPtgPers:=TO_CHAR(SYSDATE-1,'YYYYMMDD');
        ELSE 
            cJFinPtgPers:=cJFin;
        END IF;
        
        IF (cJFinPtgPers != cJFin) THEN
            cHeureFin:=TO_CHAR(SYSDATE,'HH24MISS');
        END IF;
        
        OPEN rc FOR
            SELECT *
            FROM
            (
                 SELECT TO_CHAR(POIN.jour,'YYYYMMDD') CJour,
                    POIN.heure CHeureDeb,
                    NVL(LEAD(POIN.heure) OVER (ORDER BY POIN.jour, POIN.heure), POIN.heure) CHeureFin,
                    Tps_pack.HeureDiff(POIN.heure, NVL(LEAD(POIN.heure) OVER (ORDER BY POIN.jour, POIN.heure), POIN.heure), 0) CTemps,                A.id_ligne CIdLig,
                    L.libelle CLibLig,
                    A.id_plan CIdPlan,
                    P.libelle CLibPlan,
                    A.id_fonction CIdFonc,
                    F.libelle CLibFonc,
                    A.id_operation CIdOpe,
                    O.libelle CLibOpe,
                    POIN.of_sec COfSec,
                    OO.libelle ClibOf
                FROM Pointage POIN LEFT OUTER JOIN O_f OO ON (DECODE(oth_pack.LASTALPHA(POIN.of_sec),0,POIN.of_sec,SUBSTR(POIN.of_sec,1,LENGTH(POIN.of_sec)-1))=SUBSTR(OO.of_sec,1,LENGTH(OO.of_sec)-1)),Activite A,Ligne L,Plan P,Fonction F,Operation O
                WHERE POIN.jour=TRUNC(SYSDATE)
                AND POIN.id_perso=cIdPerso
                AND POIN.id_activite=A.id_ligne||A.id_plan||A.id_fonction||A.id_operation
                AND A.id_type_ptg_sst='G'
                AND TO_CHAR(SYSDATE,'YYYYMMDD')<=TO_CHAR(A.date_fin_valide,'YYYYMMDD')
                AND A.id_ligne=L.id_ligne AND A.id_plan=P.id_plan AND A.id_fonction=F.id_fonction AND A.id_operation=O.id_operation
                AND (cJFinPtgPers != cJFin) -- CPointage n'était ouvert que sous cette condition
                UNION ALL
                SELECT TO_CHAR(PTG.jour,'YYYYMMDD') CJour,
                    PTG.heure_deb CHeureDeb,
                    PTG.heure_fin CHeureFin,
                    Tps_pack.Centi2Heure(PTG.Temps) CTemps,
                    A.id_ligne CIdLig,
                    L.libelle CLibLig,
                    A.id_plan CIdPlan,
                    P.libelle CLibPlan,
                    A.id_fonction CIdFonc,
                    F.libelle CLibFonc,
                    A.id_operation CIdOpe,
                    O.libelle CLibOpe,
                    PTG.ofs_cpt COfSec,
                    OO.libelle CLibOf
                FROM Ptg_pers PTG,Activite A,Ligne L,Plan P,Fonction F,Operation O,O_f OO
                WHERE PTG.jour>=TO_DATE(cJDeb,'YYYYMMDD') AND PTG.jour<=TO_DATE(cJFinPtgPers,'YYYYMMDD')
                AND PTG.id_perso=cIdPersoCgu
                AND PTG.id_ligne=A.id_ligne AND PTG.id_plan=A.id_plan AND PTG.id_fonction=A.id_fonction AND PTG.id_operation=A.id_operation
                AND A.id_type_ptg_sst='G'
                AND cJDeb<=TO_CHAR(A.date_fin_valide,'YYYYMMDD')
                AND A.id_ligne=L.id_ligne AND A.id_plan=P.id_plan AND A.id_fonction=F.id_fonction AND A.id_operation=O.id_operation
                AND PTG.ofs_cpt=OO.of_sec(+)
            )
            ORDER BY CJour DESC,CHeureDeb DESC,CHeureFin DESC;
            
        RETURN rc;
    
    EXCEPTION
        WHEN OTHERS THEN
            RAISE Invalid_HistoDetail;
            
    END HistoDetail;
    Dis-moi si ça fonctionne.

    La deuxième fonction semble plus facile, je vais te laisser réfléchir

    PS : les comparaisons entre TO_CHAR de dates me semblent peu appropriées : utilise plutôt TRUNC que TO_CHAR(..., 'YYYYMMDD') et si tu peux, évite d'utiliser une fonction comme TRUNC ou TO_CHAR sur une colonne qui est indexée car l'index ne pourra pas être utilisé. Tu peux par exemple comparer sans problème date_fin_valide à TRUNC(SYSDATE), mais il vaut mieux éviter TO_CHAR(date_fin_valide, ...) ou TRUNC(date_fin_valide) quand c'est possible.

  12. #12
    Membre actif
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    178
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 178
    Points : 220
    Points
    220
    Par défaut
    Citation Envoyé par mnitu Voir le message
    Et tu ne veux pas regarder les fonctions pipelined ?
    Personnellement, si on peut s'en passer, je m'en passerais, pas toi ?

  13. #13
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    171
    Détails du profil
    Informations personnelles :
    Âge : 55

    Informations forums :
    Inscription : Juin 2008
    Messages : 171
    Points : 65
    Points
    65
    Par défaut PL/SQL, PHP et Tableaux
    Bonjour Rbaraer,

    J'ai testé ta fonction, cela fonctionne parfaitement.
    Je ne connaissais pas la fonction LEAD, elle n'est même pas citée dans mon livre "Oracle9i SQL et PL/SQL".

    Pour la seconde fonction, je pensais faire un GROUP BY, mais le problème est pour cumuler les temps.

    Merci vraiment de m'accorder de ton temps.
    Si je dois signer quelque part pour que tu sois élu "Best PL/SQL Programmer of the week" dit le moi.

    Mnitu, je vais regarder aux fonctions pipelined dés que j'ai un peu de temps. Merci également.

  14. #14
    Membre actif
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    178
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 178
    Points : 220
    Points
    220
    Par défaut
    Citation Envoyé par mortimer.pw Voir le message
    Bonjour Rbaraer,

    J'ai testé ta fonction, cela fonctionne parfaitement.
    Super !

    Citation Envoyé par mortimer.pw Voir le message
    Je ne connaissais pas la fonction LEAD, elle n'est même pas citée dans mon livre "Oracle9i SQL et PL/SQL".
    LEAD est une fonction analytique qui permet d'accéder aux enregistrements suivants dans le résultat d'une requête, en fonction d'un certain regroupement (aucun ici) et d'un certain tri (par date et heure ici). Si tu es en version 9i tu trouveras la doc ici.

    Il y a beaucoup d'autres fonctions analytiques qui peuvent s'avérer très pratiques. La fonction LAG fait l'inverse de LEAD : elle permet d'accéder aux enregistrements précédents.

    Attention : les fonctions analytiques ne touchent qu'au RESULTAT FINAL de la requête pour calculer des champs supplémentaires, elles sont appliquées en tout dernier traitement, contrairement aux fonctions aggrégatives classiques. Plus d'infos dans la doc .

    Citation Envoyé par mortimer.pw Voir le message
    Pour la seconde fonction, je pensais faire un GROUP BY, mais le problème est pour cumuler les temps.
    Oui le principe est un GROUP BY puis un calcul du nombre de secondes puisque tu stockes la durée jusqu'à la seconde, quelque chose comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    SELECT SUM(
        TO_NUMBER(SUBSTR(duree, 1, 2)) * 3600 + 
        TO_NUMBER(SUBSTR(duree, 3, 2)) * 60 + 
        TO_NUMBER(SUBSTR(duree, 5, 2))) DureeEnSecondes
    FROM Ptg_Pers;
    Tu peux ensuite retrouver le nombre de jours en divisant par 3600, d'heures en divisant par 60 le reste, puis de secondes avec le reste du reste .

    Citation Envoyé par mortimer.pw Voir le message
    Si je dois signer quelque part pour que tu sois élu "Best PL/SQL Programmer of the week" dit le moi.
    C'est gentil merci

  15. #15
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    171
    Détails du profil
    Informations personnelles :
    Âge : 55

    Informations forums :
    Inscription : Juin 2008
    Messages : 171
    Points : 65
    Points
    65
    Par défaut PL/SQL, PHP et Tableaux
    Bonjour tout le monde,

    Quelqu'un sait-il si la même chose est possible sous PostgreSQL, à savoir l'utilisation des fonctions analytiques LAG/LEAD pour récupérer les valeurs des lignes précédentes et suivantes ?

  16. #16
    Membre actif
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    178
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 178
    Points : 220
    Points
    220
    Par défaut
    Citation Envoyé par mortimer.pw Voir le message
    Bonjour tout le monde,

    Quelqu'un sait-il si la même chose est possible sous PostgreSQL, à savoir l'utilisation des fonctions analytiques LAG/LEAD pour récupérer les valeurs des lignes précédentes et suivantes ?
    Non, mais ça semble bien parti pour la prochaine version (8.4) qui devrait implémenter les "window functions" de la norme SQL:2003, ce qui correspond à peu près aux fonctions analytiques d'Oracle, incluant LEAD et LAG :

    http://developer.postgresql.org/inde...:WishlistFor84

    http://wiki.postgresql.org/wiki/SQL2...dowing_queries

  17. #17
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    171
    Détails du profil
    Informations personnelles :
    Âge : 55

    Informations forums :
    Inscription : Juin 2008
    Messages : 171
    Points : 65
    Points
    65
    Par défaut PL/SQL, PHP et Tableaux
    Bonjour Rbaraer,

    Tu es vraiment incollable.

    Je vais devoir trouver une autre solution pour "alimenter" mon développeur PHP qui ne va pas attendre la 8.4.

    Je dois impérativement écrire les même fonctions pour Oracle et PostgreSQL.

    Je clôture cette discussion, merci encore pour tout.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 6
    Dernier message: 25/09/2009, 13h28
  2. [MySQL] Fonctions calculs SQL/PHP pour projet football
    Par spamyx dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 25/04/2006, 16h16
  3. [MySQL] Requete SQL PHP
    Par CaptainChoc dans le forum PHP & Base de données
    Réponses: 9
    Dernier message: 22/10/2005, 16h13
  4. [MySQL] Sql-Php / Requete/ Afficher l'age (aide nécessaire please)
    Par Odilon dans le forum PHP & Base de données
    Réponses: 18
    Dernier message: 21/10/2005, 09h21
  5. [SQL+php] requete a trouver
    Par theclear dans le forum Langage SQL
    Réponses: 6
    Dernier message: 11/10/2004, 09h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo