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 MySQL Discussion :

Selectionner le row max inférieur à chaque couple donné en paramètre


Sujet :

Requêtes MySQL

  1. #1
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut Selectionner le row max inférieur à chaque couple donné en paramètre
    soit la table history suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    ID group timestamp value
    1  A     1000      12.1        
    2  B     2000      2.6
    3  C     3000      9.4
    4  A     4000      4.7
    5  A     5000      -5.3
    6  B     6000      3.4
    Soit les données de query suivantes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    A,1200
    B,2500
    A,3500
    A,4700

    Je dois retourner pour chaque couple le groupe et le timestamp correspondant au timestamp max < la valeur donnée:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    group timestamp demande
    A     1000      1200
    B     2000      2500
    A     1000      3500
    A     4000      4700
    Bon l'idée est que c'est une sous query, en reprenant le groupe + le timestamp et en joignant avec cette sous-query, je retrouve la ligne correspondante dans la table et toutes les données associées

    Alors avec un seul couple, c'est facile:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT groupe, MAX(timestamp) timestamp, '1200'
    FROM history
    WHERE timestamp < 1200 AND groupe = 'A'
    La méthode naive avec plusieurs c'est
    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
    SELECT groupe, MAX(timestamp) timestamp, '1200'
    FROM history
    WHERE timestamp < 1200 AND groupe = 'B'  
    UNION
    SELECT groupe, MAX(timestamp) timestamp, '2500'
    FROM history
    WHERE timestamp < 1200 AND groupe = 'B'  
    UNION
    SELECT groupe, MAX(timestamp) timestamp, '3500'
    FROM history
    WHERE timestamp < 3500 AND groupe = 'A'  
    UNION
    SELECT groupe, MAX(timestamp) timestamp, '4700'
    FROM history
    WHERE timestamp < 4700 AND groupe = 'A'
    Mais c'est pas top top coté perfs.

    Je précise que la table concernée fait plusieurs millions de lignes

    En fait il me manque quelque chose dans

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT groupe, MAX(timestamp) timestamp, ??quoi??
    FROM history
    WHERE (timestamp < 1200 AND groupe = 'A'  ) OR
             (timestamp < 2500 AND groupe = 'B'  ) OR
             (timestamp < 3500 AND groupe = 'A' )  OR
             (timestamp < 4700 AND groupe = 'A'  )
    GROUP BY groupe, ??quoi??

    Alternativement, si quelqu'un a un moyen simple de retourner toutes les lignes de la tables qui correspondent directement au critere "ligne max telle que timestamp < ? et groupe = ?, pour chaque paire.
    Il y a une clé sur le couple timestamp/groupe pour aider les perfs.

  2. #2
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Comme ceci, peut-être ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    SELECT tmp.group, tmp.demande,
    	MAX(tmp.timestamp) AS timestamp_max
    FROM
    (
    	SELECT h.group, h.timestamp, q.demande
    	FROM query q
    	LEFT JOIN history h
    		ON h.group = q.group
    		AND h.timestamp < q.demande
    ) tmp
    GROUP BY tmp.group, tmp.demande
    La sous-requête donne tous les timestamps inférieurs à la demande pour chaque groupe.
    La requête principale ne conserve que le timestamp maxi pour chaque groupe.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  3. #3
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Le truc c'est que j'ai pas besoin des données "pour chaque groupe", mais des données pour chaque paire <groupe,timestamp> faisant partie de la demande.
    Prendre tous les groupes est trop peux performant. Il y en a des centaines pour une demande de 4 à 5 éléments et ça va brasser toute la table. Autant dire que je sortirais pas le résultat en mopins d'une seconde.
    Un groupe peut être présent plusieurs fois dans la demande avec un timestamp différent.

    pour faire simple, j'ai besoin pour le groupe A, du dernier timestamp < 1200, du dernier timestamp <3500 et du dernier timestamp < 4700 ainsi que pour le groupe B du dernier timestamp < 2500

    En gros je dois sortir N bloc/ranges de la base (ça je sais faire sans soucis et chaque bloc contient un segment d'un groupe) et pour chaque bloc ainsi sorti, je dois retrouver la dernière entrée dans cette table qui précède le premier élément du bloc, pour le même groupe que le bloc

    Bon après analyse, le client ne demande finalement plus tous ces blocs dans la même requete mais demandera un seul bloc (du coup là j'avais déjà la requête), mais pour ma culture, me demande si le besoin était exprimable autrement qu'en faisant N UNION avec la même requete et des paramètres différents.

  4. #4
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    As-tu essayé ma requête ?
    C'est quand même ensembliste comme démarche ; ça peut peut-être aller très vite.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  5. #5
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    arf, mes yeux n'avaient pas vu le from query q dans ton exemple Je la tente demain sur la vraie table après adaptation.

    Ca ressemble à ce que j'avais tenté. A ceci prêt que le "query q" était remplacée par une union de select from dual pour créer la table temporaire avec les paramètre de requête. C'était 10 fois plus lent à tourner que faire une union des résultats individuels

    Par contre un truc me turlupine, je vois pas dans la subquery ce qui force mysql à sélectionner le plus grand timestamp inférieur. On dirait que tu fais la jointure avec tous les timestamps < dans ton left join et que tu filtre en aval. Je suis pas expert en mysql, mais ça va pas le forcer à brasser toutes les lignes qui matchent timestamp < plutot que de sauter directement au dernier?

  6. #6
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    On dirait que tu fais la jointure avec tous les timestamps < dans ton left join et que tu filtre en aval.
    Oui, c'est ça :
    Citation Envoyé par CinéPhil
    La sous-requête donne tous les timestamps inférieurs à la demande pour chaque groupe.
    La requête principale ne conserve que le timestamp maxi pour chaque groupe.
    Je suis pas expert en mysql, mais ça va pas le forcer à brasser toutes les lignes qui matchent timestamp < plutot que de sauter directement au dernier?
    Le problème est justement de trouver le dernier pour chaque bloc de query.
    Peut-être qu'il y aurait une meilleure solution avec des fonctions analytiques mais comme MySQMerde ne les connaît toujours pas...
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  7. #7
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Disons que la table en question a un index sur groupe / timestamp

    Quand je fais la recherche avec une seule paire (timestamp < ? and groupe = ?) +MAX, mysql s'en sort correctement en utilisant juste l'index BTREE en recherche dychotomique. Du coup la recherche est très rapide.

    Je dois toujours tester ta requete, pas eu le temps, mais je vais essayer la semaine prochaine

Discussions similaires

  1. [AC-2007] Selectionner la valeur max d'un champ pour chaque donnee d'un autre champ
    Par Benj24 dans le forum Requêtes et SQL.
    Réponses: 2
    Dernier message: 15/04/2010, 03h14
  2. Selectionner une row dans DataGridView
    Par boulo dans le forum Windows Forms
    Réponses: 3
    Dernier message: 28/03/2007, 00h17
  3. [Requête] faire la somme des max pour chaque utilisateur
    Par novices dans le forum Langage SQL
    Réponses: 3
    Dernier message: 13/02/2007, 11h45
  4. Comment selectionner un row dans DBGrid par programmation
    Par lingli dans le forum Bases de données
    Réponses: 3
    Dernier message: 29/06/2006, 12h58
  5. une requête qui selectionne la ligne max
    Par kuhnden dans le forum Access
    Réponses: 3
    Dernier message: 01/11/2005, 18h39

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