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

Requêtes PostgreSQL Discussion :

Jointure sur le résultat d'une fonction dépendant d'un paramètre de la table jointe [9.2]


Sujet :

Requêtes PostgreSQL

  1. #1
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Points : 18 681
    Points
    18 681
    Par défaut Jointure sur le résultat d'une fonction dépendant d'un paramètre de la table jointe
    Bonsoir,


    J'ai un léger soucis pour concrétiser une requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    WITH a AS ( 
       SELECT id FROM MaFonction()
    )
    SELECT a.id AS "a_id", b.* FROM 
       a CROSS JOIN (
          SELECT * FROM SecondeFonction(a.id)
       ) AS b
    le hic étant que je ne peux apparemment pas utiliser a.id dans la définition de b


    Actuellement, je suis obligé de passer par du procédural



    par avance

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 915
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 915
    Points : 51 691
    Points
    51 691
    Billets dans le blog
    6
    Par défaut
    C'est normal. PostGreSQL ne propose pas d'opérateur pour ce que l'on appelle l'intra jointure.

    C'est implémenté sous SQL Server, sous la forme :
    CROSS APPLY (pour un produit cartésien)
    OUTER APPLY (dans le cas ou aucune ligne ne serait renvoyée par la fonction table).


    Vous êtes aux limites de PG !

    Et cela pose même des problèmes de perf...
    Lisez l'article que j'ai écrit à ce sujet :
    http://blog.developpez.com/sqlpro/p9...alles_en_sql_1
    Dans ces requêtes, les meilleurs temps de calcul sont obtenus par SQL Server, grace à CROSS APPLY !!!

    A +

  3. #3
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Points : 18 681
    Points
    18 681
    Par défaut
    pour la réponse

    Citation Envoyé par SQLpro Voir le message
    C'est normal. PostGreSQL ne propose pas d'opérateur pour ce que l'on appelle l'intra jointure.
    Je n'ai pas tellement de choix... si ça grossit trop, j'aurais sûrement moyen d'avoir Oracle au lieu de PostgreSQL si mon proto remplit les besoins fonctionnels

    Citation Envoyé par SQLpro Voir le message
    Vous êtes aux limites de PG !
    J'ai du passer par une technique plus procédurale pour casser en deux étapes, ça prend moins de 5min... mais j'aurais préféré un truc propre du premier coup

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    1 874
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 874
    Points : 2 890
    Points
    2 890
    Par défaut
    J'imagine que SecondeFonction() renvoie du SET OF quelquechose ou du TABLE(...)

    Il me semble que ce tu veux faire s'écrit simplement comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT a.id,SecondeFonction(a.id)
    FROM (SELECT id FROM MaFonction()) a;
    ou si SecondeFonction renvoie un type composite, avec cette variante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT a.id, (SecondeFonction(a.id)).*
    FROM (SELECT id FROM MaFonction()) a;
    Si ça ne passe pas, précise ce que renvoient exactement les fonctions car c'est la clef du problème.

  5. #5
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Points : 18 681
    Points
    18 681
    Par défaut
    elle renvoie un Set Of

    la requête est syntaxiquement correcte, mais horriblement lente comparée au patch procédural que j'utilise pour le moment


    pour l'astuce

  6. #6
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 915
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 915
    Points : 51 691
    Points
    51 691
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par gorgonite Voir le message
    pour la réponse

    Je n'ai pas tellement de choix... si ça grossit trop, j'aurais sûrement moyen d'avoir Oracle au lieu de PostgreSQL si mon proto remplit les besoins fonctionnels
    Oracle ne supporte pas non plus cette forme de jointure. A ma connaissance ceci n'est implémenté que sous MS SQL Server.

    A +

  7. #7
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Sr. Specialist Solutions Architect @Databricks
    Inscrit en
    Septembre 2008
    Messages
    8 453
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Sr. Specialist Solutions Architect @Databricks
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 453
    Points : 18 391
    Points
    18 391
    Par défaut
    Citation Envoyé par SQLpro Voir le message
    Oracle ne supporte pas non plus cette forme de jointure. A ma connaissance ceci n'est implémenté que sous MS SQL Server.
    Ça existe chez Oracle Database depuis la 9i (commercialisée en 2001) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select * from table(mafonction(mesparam));
    http://docs.oracle.com/cd/E11882_01/...ing.htm#i52954

  8. #8
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 915
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 915
    Points : 51 691
    Points
    51 691
    Billets dans le blog
    6
    Par défaut
    Waldar, je en conteste pas que les fonctions table existent dans Oracle, mais pas l'intra-jointure avec APPLY, ce que fait SQL Server....

    A +

  9. #9
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2008
    Messages
    2 950
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2008
    Messages : 2 950
    Points : 5 849
    Points
    5 849
    Par défaut
    Oracle n'a pas le mot clé APPLY mais il n'en a pas besoin pour faire l'intra jointure avec CROSS JOIN.
    Avec le code oracle suivant :
    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
    create or replace type t_weekday_obj as object (DTE DATE, JOUR VARCHAR2(8))
    /
    create or replace type t_weekday_table as table of t_weekday_obj;
    /
     
    CREATE or replace FUNCTION F_WEEKDAYTABLE (A_DATE DATE) 
    RETURN t_weekday_table as
      l_date date;
      l_res t_weekday_table := t_weekday_table();
    BEGIN 
    -- obtention de la date avec heure 0 
       l_date := trunc(a_date); 
    -- recherche du lundi 
       WHILE to_char(l_date, 'fmDAY', 'NLS_DATE_LANGUAGE = french') <> 'LUNDI' loop
             l_date := l_date - 1;
       end loop;   
    -- insertion des jours de la semaine dans la table 
       l_res.extend;
       l_res(l_res.last) := t_weekday_obj(l_date,'Lundi');
       l_res.extend;
       l_res(l_res.last) := t_weekday_obj(l_date + 1,'Mardi');
       l_res.extend;
       l_res(l_res.last) := t_weekday_obj(l_date + 2,'Mercredi');
       l_res.extend;
       l_res(l_res.last) := t_weekday_obj(l_date + 3,'Jeudi');
       l_res.extend;
       l_res(l_res.last) := t_weekday_obj(l_date + 4,'Vendredi');
       l_res.extend;
       l_res(l_res.last) := t_weekday_obj(l_date + 5,'Samedi');
       l_res.extend;
       l_res(l_res.last) := t_weekday_obj(l_date + 6,'Dimanche');
    -- retour   
       RETURN l_res;
    END;
    /
    On obtient :
    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
    SQL> SELECT *
      2    FROM T_FACTURE_FCT F
      3   CROSS JOIN table(F_WEEKDAYTABLE(f.FCT_DATE)) W
      4   WHERE W.JOUR = 'Jeudi' ;
     
        FCT_ID FCT_DATE     CLI_ID DTE      JOUR
    ---------- -------- ---------- -------- --------
           145 18/07/05         33 21/07/05 Jeudi
           178 20/07/05         21 21/07/05 Jeudi
           213 22/07/05         47 21/07/05 Jeudi
     
    SQL> SELECT FCT_ID, FCT_DATE, CLI_ID,
      2         CASE
      3            WHEN FCT_DATE > W.DTE THEN WW.DTE
      4            ELSE W.DTE
      5         END AS DATE_ENVOI
      6    FROM T_FACTURE_FCT F
      7         CROSS JOIN table(F_WEEKDAYTABLE (F.FCT_DATE)) W
      8         CROSS JOIN table(F_WEEKDAYTABLE (F.FCT_DATE + 7)) WW
      9   WHERE W.JOUR  = 'Jeudi'
     10     AND WW.JOUR = 'Jeudi';
     
        FCT_ID FCT_DATE     CLI_ID DATE_ENV
    ---------- -------- ---------- --------
           145 18/07/05         33 21/07/05
           178 20/07/05         21 21/07/05
           213 22/07/05         47 28/07/05
     
    SQL>

  10. #10
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Points : 18 681
    Points
    18 681
    Par défaut
    question bête... la jointure latérale de postgresql 9.3 résoudrait-elle mon problème (si j'en crois l'exemple)

  11. #11
    Rédacteur/Modérateur

    Avatar de gorgonite
    Homme Profil pro
    Ingénieur d'études
    Inscrit en
    Décembre 2005
    Messages
    10 322
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur d'études
    Secteur : Transports

    Informations forums :
    Inscription : Décembre 2005
    Messages : 10 322
    Points : 18 681
    Points
    18 681
    Par défaut
    Pour infos, il semble que la version avec JOIN LATERAL soit bien plus lente que la version avec CTE

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    With h As (
       Select Fonction1, Fonction2(arg,Fonction1) From Fonction1(arg)
    )
    Select h.Fonction1, mv.* 
       From Main_View mv 
          Inner Join h On (id=h.Fonction2)
       Order By h.Fonction1, mv.Id
    vs

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Select h.Fonction1, mv.* 
       From Main_View mv 
          Left Join Lateral (
             Select Fonction1, Fonction2(arg,Fonction1) From Fonction1(arg)
          ) As h On ( id=h.Fonction2 )
       Order By h.Fonction1, mv.Id
    Fonction1 prend un argument de type T et renvoie un set of bigint
    Fonction2 prend un argument de type T ainsi qu'un bigint, et renvoie un set of bigint


    C'était juste pour tester...

  12. #12
    Rédacteur

    Homme Profil pro
    Consultant / formateur Oracle et SQL Server
    Inscrit en
    Décembre 2002
    Messages
    3 461
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant / formateur Oracle et SQL Server

    Informations forums :
    Inscription : Décembre 2002
    Messages : 3 461
    Points : 8 079
    Points
    8 079
    Par défaut
    Citation Envoyé par skuatamad Voir le message
    Oracle n'a pas le mot clé APPLY ...
    Entre temps, Oracle 12c est sortie, et désormais les syntaxes LATERAL, CROSS APPLY et OUTER APPLY sont disponibles.

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

Discussions similaires

  1. [MySQL] Fonctions de trie sur un résultat d'une requête
    Par sara21 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 22/02/2015, 07h00
  2. Retour a la ligne sur le résultat d'une fonction
    Par bastounseb dans le forum Langage
    Réponses: 9
    Dernier message: 01/10/2014, 01h59
  3. Réponses: 0
    Dernier message: 16/03/2012, 10h03
  4. Réponses: 5
    Dernier message: 13/10/2005, 12h46
  5. [Firebird] DELETE sur le résultat d'une requete d'un IBQUERY
    Par shashark dans le forum Bases de données
    Réponses: 3
    Dernier message: 25/06/2005, 18h17

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