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

Langage SQL Discussion :

Problème d'efficacité sur une requête


Sujet :

Langage SQL

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2015
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Mai 2015
    Messages : 15
    Points : 14
    Points
    14
    Par défaut Problème d'efficacité sur une requête
    Bonjour à tous ,

    J'ai une requête sql à faire et je sollicite votre aide.

    Pour simplifier, j'ai une base principale de contrats un id_client et une certaine date DATE_T.
    BASE1 :
    ...
    Id_client
    DATE_T

    J'ai une une autre base de contrats dans laquelle j'ai également un id_client ainsi que deux dates DATE_DEB et DATE_FIN
    BASE2 :
    Id_client
    Prix1
    Prix2
    DATE_DEB
    DATE_FIN


    EN partant de BASE1 j'aimerais compter le nombre de contrats de la BASE2, la moyenne de Prix1 associées ainsi que celle de Prix2 vérifiant les 2 conditions suivantes :

    BASE1.id_client = BASE2.id_client
    BASE2.DATE_DEB <= BASE1.DATE_T <= BASE2.DATE_FIN


    Je vous présente ma solution actuelle qui prend énormément de temps notamment à cause de la conditions sur les dates :

    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
     
    CREATE TABLE Tab AS
     
        SELECT 
     
        BASE1.*,
     
        (SELECT count(*) FROM BASE2 WHERE BASE1.id_client = BASE2.id_client 
                                         AND BASE2.DATE_DEB <= BASE1.DATE_T <= BASE2.DATE_FIN) as NB_CT,
     
        (SELECT mean(Prix1) FROM BASE2 WHERE BASE1.id_client = BASE2.id_client 
                                              AND BASE2.DATE_DEB <= BASE1.DATE_T <= BASE2.DATE_FIN) as Prix1Moy,
     
        (SELECT mean(Prix2) FROM BASE2 WHERE BASE1.id_client = BASE2.id_client 
                                              AND BASE2.DATE_DEB <= BASE1.DATE_T <= BASE2.DATE_FIN) as Prix2Moy
     
     
    FROM BASE1;

    J'aimerais savoir comment vous auriez codé cette requête car je dois vraiment abandonner cette méthode qui prend un temps fou .
    J'ai pensé à utiliser la fonction OVER PARTITION BY mais sans succès.


    Merci d'avance à ceux qui prendront le temps d'y jeter un œil.

  2. #2
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 378
    Points : 39 860
    Points
    39 860
    Billets dans le blog
    9
    Par défaut
    Bonjour,

    Vous voulez compter le nombre de contrats, très bien, mais à quoi reconnait on un contrat dans l'une et l'autre table ?
    N'y a -t- il pas une colonne numéro de contrat, identifiant contrat ou autre ?
    Ou alors faut il considérer que dans chacune des deux tables, un contrat est unique pour une personne identifiée par (insee_code + sexe + date de naissance)

    Question subsidiaire : le code insee (s'il s'agit bien du n° de sécu ou équivalent) est normalement unique, du coup inutile d'y ajouter le sexe et la date de naissance pour reconnaitre une personne. Peut être avez vous ajouté ces critères si dans votre base de données, les enfants par exemple ont le n° insee du père ou de la mère ?

    Et une remarque : pour obtenir le prix mini, il faut coder min(prix) et non pas mean(prix)

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2015
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Mai 2015
    Messages : 15
    Points : 14
    Points
    14
    Par défaut
    Bonjour et merci pour votre réponse.

    Non il peut y avoir plusieurs contrats de la BASE2 qui vérifient les 4 conditions.
    Oui effectivement chaque ligne des deux tables correspond à un contrat unique avec un numéro de contrat associé.

    Non le code insee est un code géographique (assez proche du code postale).

    En fait, insee_code + sexe + date de naissance est un proxy d'un "Id_client" malheureusement absent de la base de données.

    Je le remplace par id_client car ça complique inutilement le sujet :

    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
     
    CREATE TABLE Tab AS
     
        SELECT 
     
        BASE1.*,
     
        (SELECT count(*) FROM BASE2 WHERE BASE1.Id_client = BASE2.Id_client
                                         AND BASE2.DATE_DEB <= BASE1.DATE_T <= BASE2.DATE_FIN) as NB_CT,
     
        (SELECT mean(Prix1) FROM BASE2 WHERE BASE1.Id_client = BASE2.Id_client
                                              AND BASE2.DATE_DEB <= BASE1.DATE_T <= BASE2.DATE_FIN) as Prix1Moy,
     
        (SELECT mean(Prix2) FROM BASE2 WHERE BASE1.Id_client = BASE2.Id_client
                                              AND BASE2.DATE_DEB <= BASE1.DATE_T <= BASE2.DATE_FIN) as Prix2Moy
     
     
    FROM BASE1;

  4. #4
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 378
    Points : 39 860
    Points
    39 860
    Billets dans le blog
    9
    Par défaut
    Utilisez une CTE ou une table dérivée
    EDIT : oups pardon, j'ai oublié le problème de plage de dates

  5. #5
    Rédacteur/Modérateur

    Homme Profil pro
    Ingénieur qualité méthodes
    Inscrit en
    Décembre 2013
    Messages
    4 144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur qualité méthodes
    Secteur : Conseil

    Informations forums :
    Inscription : Décembre 2013
    Messages : 4 144
    Points : 9 592
    Points
    9 592
    Par défaut
    J'aurais vu une requête comme celle-ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    CREATE TABLE Tab AS
    SELECT  
        BASE1.id_client ,   min(base1.nom) as nom, min(base1.prenom)  as prenom ... ... 
        count(*) as NB_CT , avg( prix1) as Prix1Moy, avg(Prix2) as Prix2Moy
    from BASE1, BASE2
    where BASE1.id_client = BASE2.id_client 
       and base1.date_T between base2.date_deb and base2.date_fin
    group by base1.id_client
    1. J'ai remplacé Mean() par avg() ; peut-être que Mean() fait le job, je ne connais pas.
    2. J'imagine que dans base1, pour un id_client, on a une seule ligne. Du coup, je récupère min(Nom), mais je pourrais récupérer max(nom), ça donnerait exactement le même résultat. Si dans base1, il peut y avoir plusieurs lignes avec le même id_client, alors faut mieux expliquer l'organisation des données.
    3. Si pour un id_client, il n'y a aucune ligne dans base2 avec les contraintes de date, cette requête va "perdre" ce id_client alors que ta requête d'origine ne les perdait pas. Si tu veux garder ces lignes, il faut adapter avec des outer_join.
    4. J'ai utilisé la syntaxe where BASE1.id_client = BASE2.id_client ; certains prèfèrent qu'on écrive inner join base2 on ...
    5. En terme de performance, ça devrait aller 100 fois ou 1000 fois plus vite que la requête d'origine. Accessoirement, ce serait bien de préciser si tu as un index sur la colonne id_client dans ces 2 tables. Et si tu n'en as pas, il faut peut-être en créer un.

  6. #6
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2015
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Finance

    Informations forums :
    Inscription : Mai 2015
    Messages : 15
    Points : 14
    Points
    14
    Par défaut
    Ça marche nickel !

    Merci bcp

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

Discussions similaires

  1. [10gR2] Problème de lenteur sur une requête
    Par daddy2014 dans le forum SQL
    Réponses: 1
    Dernier message: 15/07/2014, 19h18
  2. Problème de totalisation sur une requête
    Par lodan dans le forum Requêtes
    Réponses: 3
    Dernier message: 30/11/2009, 19h40
  3. Problème de SUM sur une requête SQL
    Par Lapicure dans le forum Requêtes et SQL.
    Réponses: 1
    Dernier message: 12/06/2007, 12h51
  4. Problème avec coun(*) sur une requête
    Par Kaoru-tabris dans le forum Requêtes
    Réponses: 1
    Dernier message: 10/03/2007, 16h00
  5. [MSDE] Problème de groupage sur une requête
    Par joefou dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 17/11/2006, 10h43

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