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

Développement SQL Server Discussion :

Sous-requête dans un FROM ou table temporaire


Sujet :

Développement SQL Server

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 31
    Points : 19
    Points
    19
    Par défaut Sous-requête dans un FROM ou table temporaire
    Bonjour à tous,

    voila quelques heures que je débugge une requête et je m'aperçois que le comportement est différent si je mets une sous-requête dans un FROM ou si je mets cette même sous-requête dans une table temporaire et que je l'utilise ensuite dans une requête.

    concrètement, je ne comprend pas comment une sous-requête "stand alone" peut renvoyer des résultats différents selon son mode d'utilisation.

    Si quelqu'un peut m'expliquer, je suis preneur.
    Merci.

    (A noter que la sous-requête contient une jointure externe. A noter également que c'est l'utilisation d'un critère sur la sous-requête qui semble changer le comportement)

    Voici les 2 méthodes:

    Méthode avec la sous-reuqête dans le FROM
    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
     
    select tmp1.DateDebutAppartenance
           , tmp1.DateFinAppartenance
           , getdate()+45 PlageDebut
           , getdate()+90 PlageFin
           , utilisateurprosodie.*
           , utilisateur.login
           , utilisateur.DateDebutValide
           , utilisateur.DateFinValide
           , utilisateur.Nom
           , utilisateur.Prenom
           , utilisateur.TelephoneFixe
           , utilisateur.TelephoneMobile
           , Convert(varchar(8000), utilisateur.Commentaire) as Commentaire
           , utilisateur.Actif
           , utilisateur.Email from utilisateurprosodie
           , utilisateur
           ,  (
                select h.idutilisateur
              , h.propriete
              , h.valeur
              , h.datemodification DateDebutAppartenance
              , isnull(h2.datemodification,getdate()+99999) DateFinAppartenance
               from historiquedonneesadministratives h
                    , historiquedonneesadministratives h2
               where h.propriete=2 
                  and h.valeur=52 
                  and h2.idhistoriqueadmin=*
                        (select top 1 idhistoriqueadmin 
                         from historiquedonneesadministratives h3 
                         where h3.propriete=2 
                             and h3.idutilisateur=h.idutilisateur 
                             and h3.datemodification>h.datemodification 
                          order by h3.datemodification asc)
    ) tmp1 /*Date de début et de fin d'appartenance à une EO*/
    where utilisateur.idutilisateur=utilisateurprosodie.idutilisateur
    and tmp1.idutilisateur=utilisateurprosodie.idutilisateur 
    and (tmp1.DateDebutAppartenance between getdate()+45 and getdate()+90 
    or tmp1.DateFinAppartenance between getdate()+45 and getdate()+90
    or getdate()+45 between tmp1.DateDebutAppartenance and tmp1.DateFinAppartenance
    or getdate()+90 between tmp1.DateDebutAppartenance and tmp1.DateFinAppartenance)
    Résultat:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    2008-09-23 10:44:58.430    2282-09-12 14:05:32.003    2009-01-12 14:05:32.003    2009-02-26 14:05:32.003    2261    0661213527    3013    NULL    1108    52    70300000    5    2    NULL    NULL    NULL    0    NULL    NULL    njamin    2007-07-02 00:00:00.000    NULL    JAMIN    NADINE    0146841131    0146841131    NULL    1    njamin@prosodie.com
    Méthode avec la sous-reuqête dans une table temporaire:
    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
     
    CREATE TABLE #tmp (idutilisateur int, propriete int, valeur tinyint, DateDebutAppartenance datetime, DateFinAppartenance datetime);
    INSERT INTO #tmp select h.idutilisateur, h.propriete, h.valeur, h.datemodification DateDebutAppartenance, 
        isnull(h2.datemodification,getdate()+99999) DateFinAppartenance
        from historiquedonneesadministratives h, historiquedonneesadministratives h2
        where h.propriete=2 and h.valeur=52 and h2.idhistoriqueadmin=*
        (select top 1 h3.idhistoriqueadmin from historiquedonneesadministratives h3   
        where h3.propriete=2 and h3.idutilisateur=h.idutilisateur and h3.datemodification>h.datemodification 
        order by h3.datemodification asc);
     
    select tmp1.DateDebutAppartenance,tmp1.DateFinAppartenance,getdate()+45 PlageDebut,getdate()+90 PlageFin, utilisateurprosodie.*, utilisateur.login, utilisateur.DateDebutValide, utilisateur.DateFinValide, utilisateur.Nom, utilisateur.Prenom, utilisateur.TelephoneFixe, utilisateur.TelephoneMobile, Convert(varchar(8000), utilisateur.Commentaire) as Commentaire, utilisateur.Actif, utilisateur.Email from utilisateurprosodie, utilisateur,  #tmp tmp1 /*Date de début et de fin d'appartenance à une EO*/
    where utilisateur.idutilisateur=utilisateurprosodie.idutilisateur
    and tmp1.idutilisateur=utilisateurprosodie.idutilisateur 
    and (tmp1.DateDebutAppartenance between getdate()-45 and getdate()+90 
    or tmp1.DateFinAppartenance between getdate()-45 and getdate()+90
    or getdate()-45 between tmp1.DateDebutAppartenance and tmp1.DateFinAppartenance
    or getdate()+90 between tmp1.DateDebutAppartenance and tmp1.DateFinAppartenance)
    Résultat:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    2008-09-23 10:44:58.430    2008-12-17 16:00:13.297    2009-01-12 14:03:53.953    2009-02-26 14:03:53.953    2261    0661213527    3013    NULL    1108    52    70300000    5    2    NULL    NULL    NULL    0    NULL    NULL    njamin    2007-07-02 00:00:00.000    NULL    JAMIN    NADINE    0146841131    0146841131    NULL    1    njamin@prosodie.com
    Les résultats en gras changent... ce que je ne comprends pas.

    [Ne pas essayer de comprendre le fonctionnement des requêtes, je pense que ça n'a pas d'interet pour l'explication à priori]

    Merci pour votre aide.

  2. #2
    Scorpi0
    Invité(e)
    Par défaut
    Salut,

    getdate() te retourne l'heure actuelle non ? Dans ce cas, ça dépend a quel heure tu fais tourner tes requêtes, forcement tes données changent.

    Sinon l'année 2282 n'a pas l'air de te choquer, c'est normal ?

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    956
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 956
    Points : 1 199
    Points
    1 199
    Par défaut
    Bonjour,
    Est-ce normal que dans la version avec sous requete il y ait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    AND (tmp1.DateDebutAppartenance BETWEEN getdate()+45 AND getdate()+90
    Donc un +45

    Et que dans la version avec table temporaire il y ait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    AND (tmp1.DateDebutAppartenance BETWEEN getdate()-45 AND getdate()+90
    Un -45 moins pas plus

    Cela pourrait expliquer des différences non?
    A+
    Soazig

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 31
    Points : 19
    Points
    19
    Par défaut
    Merci pour vos réponses.

    pour le -45 ou le +45, c'est une malheureuse erreur de copier/coller dans la rédaction du post. désolé. (mais bien vu! )

    Pour ce qui est du getdate(), ça n'a pas d'importance sur la requête et sur mon problème. Les 2 requêtes sont censées retourner exactement les même résultats et ce n'est pas le cas.

    c'est difficile à expliquer mais mon problème vient du fait que ma sous-requête me renvoie des résultats données et clairement déterminés et que lorsque je requête sur ces résultats là en ajoutant des critères les résultats ne sont pas les même selon si je passe par une sous-requête dans le FROM ou par une table temporaire.

    Bonne fin de journée.

  5. #5
    Membre émérite Avatar de pacmann
    Homme Profil pro
    Consulté Oracle
    Inscrit en
    Juin 2004
    Messages
    1 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consulté Oracle
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 626
    Points : 2 845
    Points
    2 845
    Par défaut
    Salut !

    Visiblement, lorsque tu crées la table temporaire, la jointure externe sur h2.idhistoriqueadmin trouve une correspondance, alors que lors de l'exécution en un seul bloc, ça retourne NULL (et donc getdate() + 99999).

    Je ne sais pas trop comment marche SQL Server... mais il se pourrait qu'il te "merge" ton inline view...

    Est-ce que tu peux afficher le plan d'exécution pour ta requête "en un bloc" ?

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 31
    Points : 19
    Points
    19
    Par défaut
    Oui, en effet, j'ai l'impression qu'il me recalcule la sous-requête si j'ajoute des critères et modifie donc le contenu des lignes renvoyées. Ce qui fausse le résultat.

    J'ai mis le plan d'exécution en pièce jointe.
    Images attachées Images attachées  

  7. #7
    Membre émérite Avatar de pacmann
    Homme Profil pro
    Consulté Oracle
    Inscrit en
    Juin 2004
    Messages
    1 626
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Consulté Oracle
    Secteur : Distribution

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 626
    Points : 2 845
    Points
    2 845
    Par défaut
    Hmmm... (j'ai voulu faire le malin avec cette histoire de plan d'exécution, mais j'y capte pas grand chose )

    Est-ce que tu peux tenter la version avec CTE de ta requête, puis comparer les plans d'exécution ?

    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
     
     
    WITH tmp1 AS(
    (
                SELECT h.idutilisateur
              , h.propriete
              , h.valeur
              , h.datemodification DateDebutAppartenance
              , isnull(h2.datemodification,getdate()+99999) DateFinAppartenance
               FROM historiquedonneesadministratives h
                    , historiquedonneesadministratives h2
               WHERE h.propriete=2 
                  AND h.valeur=52 
                  AND h2.idhistoriqueadmin=*
                        (SELECT top 1 idhistoriqueadmin 
                         FROM historiquedonneesadministratives h3 
                         WHERE h3.propriete=2 
                             AND h3.idutilisateur=h.idutilisateur 
                             AND h3.datemodification>h.datemodification 
                          ORDER BY h3.datemodification ASC)
    ) /*Date de début et de fin d'appartenance à une EO*/
    SELECT tmp1.DateDebutAppartenance
           , tmp1.DateFinAppartenance
           , getdate()+45 PlageDebut
           , getdate()+90 PlageFin
           , utilisateurprosodie.*
           , utilisateur.login
           , utilisateur.DateDebutValide
           , utilisateur.DateFinValide
           , utilisateur.Nom
           , utilisateur.Prenom
           , utilisateur.TelephoneFixe
           , utilisateur.TelephoneMobile
           , Convert(varchar(8000), utilisateur.Commentaire) AS Commentaire
           , utilisateur.Actif
           , utilisateur.Email FROM utilisateurprosodie
           , utilisateur
           ,  tmp1
    WHERE utilisateur.idutilisateur=utilisateurprosodie.idutilisateur
    AND tmp1.idutilisateur=utilisateurprosodie.idutilisateur 
    AND (tmp1.DateDebutAppartenance BETWEEN getdate()+45 AND getdate()+90 
    OR tmp1.DateFinAppartenance BETWEEN getdate()+45 AND getdate()+90
    OR getdate()+45 BETWEEN tmp1.DateDebutAppartenance AND tmp1.DateFinAppartenance
    OR getdate()+90 BETWEEN tmp1.DateDebutAppartenance AND tmp1.DateFinAppartenance)

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 31
    Points : 19
    Points
    19
    Par défaut
    Damned, je suis sous SQL Server 2000 et WITH ne fonctionne qu'avec SQL 2005 ou + d'après ce que j'ai vu.

    Je ne pourrai pas tester. Merci pacmann pour ton acharnement.
    J'ai de toute façon utilisé la méthode avec table temporaire qui fonctionne bien même si pas très joli.

    Encore merci à tous.

Discussions similaires

  1. Réponses: 2
    Dernier message: 01/04/2014, 13h35
  2. Sous-requête dans un FROM
    Par Seb33300 dans le forum Doctrine2
    Réponses: 4
    Dernier message: 19/01/2013, 22h47
  3. Requète UPDATE avec sous-requète dans la même table.
    Par Selenite dans le forum Langage SQL
    Réponses: 6
    Dernier message: 16/03/2009, 15h04
  4. Sous requête dans un FROM en HQL
    Par mastamx dans le forum Hibernate
    Réponses: 1
    Dernier message: 20/05/2008, 14h54
  5. Sous-requête dans même table
    Par bisol dans le forum Requêtes
    Réponses: 1
    Dernier message: 27/04/2007, 09h57

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