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 :

COUNT et GROUP BY avec clause WHERE


Sujet :

Requêtes MySQL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 19
    Par défaut COUNT et GROUP BY avec clause WHERE
    bonjour,
    un problème souvent discuté mais auquel je ne trouve pas de réponse:

    j'ai une table clients comme suit:
    id : date_creation

    je veux connaitre le nombre d'inscriptions par jour, entre deux dates

    Voici la requète:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SELECT from_unixtime(date_creation,'%Y %M %D'),COUNT(id) from `clients` 
    WHERE date_creation >= '".$startTime."' AND  date_creation <= '".$endTime."' 
    GROUP BY from_unixtime(date_creation,'%Y %M %D') 
    ORDER BY date_creation asc
    qui renvoie par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    2011 August 1st 2
    2011 August 2nd 3
    2011 August 3rd 2
    2011 August 4th 2
    2011 August 5th 4
    2011 August 8th 4
    le problème étant que la requête n'envoie pas de 0 pour les jours sans inscriptions (les 6 et 7 Aout par exemple) ceci à cause de la clause where

    la seule solution est de faire des tables de jours des mois avec un join dessus ?

    Merci pour vos conseils éclairés

    Note: la structure de la table est ce qu'elle est, (champs date qui est un time() dans un varchar)

  2. #2
    ced
    ced est déconnecté
    Rédacteur/Modérateur

    Avatar de ced
    Homme Profil pro
    Gestion de bases de données techniques
    Inscrit en
    Avril 2002
    Messages
    6 063
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : Gestion de bases de données techniques
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Avril 2002
    Messages : 6 063
    Par défaut
    Bonjour,
    Citation Envoyé par mickey45 Voir le message
    la seule solution est de faire des tables de jours des mois avec un join dessus ?
    Oui, il te faut une table pivot avec toutes les dates sur laquelle t'appuyer pour pouvoir faire ça.
    Une table temporaire générée avant chaque requête, par exemple.
    Rédacteur / Modérateur SGBD et R
    Mes tutoriels et la FAQ MySQL

    ----------------------------------------------------
    Pensez aux balises code et au tag
    Une réponse vous a plu ? N'hésitez pas à y mettre un
    Je ne réponds pas aux questions techniques par message privé, les forums sont là pour ça

  3. #3
    Membre chevronné
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2011
    Messages
    271
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Italie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2011
    Messages : 271
    Par défaut
    Tu pourrais créer une table de 0 a 9 et avec des CROSS JOIN sur cette meme table pour avoir une table d'entier. Ajouter chaque entier a la date de départ et vérifier si elle ne dépasse pas la date d'arrivée.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    CREATE TABLE num (i int);
    INSERT INTO num (i) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);
    Ensuite tu fait un LEFT JOIN sur la colonne date_creation

    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
    SELECT a.date_creation, b.nombre from
    (SELECT adddate( '2011-08-01', numlist.id ) AS date_creation
    FROM (
    SELECT n1.i + n10.i *10 + n100.i *100 AS id
    FROM num n1
    CROSS JOIN num AS n10
    CROSS JOIN num AS n100
    ) AS numlist
    WHERE adddate( '2011-08-01', numlist.id ) <= '2011-08-31') a
    LEFT JOIN
    (SELECT date_creation, COUNT(id) as nombre FROM clients
    WHERE date_creation BETWEEN '2011-08-01' AND '2011-08-31' 
    GROUP BY date_creation
    ORDER BY date_creation ASC
    ) AS b
    ON a.date_creation=b.date_creation
    On peux aussi créer une table d'entier ( de 0 a n) une fois pour toute et éviter les CROSS JOIN. (n: maximum de difference entre deux dates)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    SELECT a.date_creation, b.nombre
    FROM (
        SELECT ADDDATE( '2011-08-01', i ) AS date_creation
        FROM Num
        WHERE i BETWEEN 0 AND DATEDIFF('2011-08-31', '2011-08-01')
    ) AS a
    LEFT JOIN 
    (SELECT date_creation, COUNT(id) as nombre FROM clients
    WHERE date_creation BETWEEN '2011-08-01' AND '2011-08-31' 
    GROUP BY date_creation
    ORDER BY date_creation ASC
    ) AS b
    ON a.date_creation = b.date_creation

  4. #4
    Membre Expert Avatar de Yanika_bzh
    Homme Profil pro
    Responsable Applicatif et R&D
    Inscrit en
    Février 2006
    Messages
    1 144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Responsable Applicatif et R&D
    Secteur : Finance

    Informations forums :
    Inscription : Février 2006
    Messages : 1 144
    Par défaut
    Citation Envoyé par fab256 Voir le message
    Tu pourrais créer une table de 0 a 9 pour générer la liste des dates de ton intervale
    Mince, moi qui croyais qu'une année comportait 12 mois !

    Sinon, y'a surement de quoi faire votre bonheur dans ce petit papier

  5. #5
    Membre chevronné
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2011
    Messages
    271
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Italie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2011
    Messages : 271
    Par défaut
    On peux encore faire mieux! Sans table temporaire, sans boucle, et sans procédure.
    On remplace la table num dans le code précédent
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    CREATE TABLE num (i int);
    INSERT INTO num (i) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);
    Par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    SELECT 0 AS i
    UNION ALL SELECT 1
    UNION ALL SELECT 2
    UNION ALL SELECT 3
    UNION ALL SELECT 4
    UNION ALL SELECT 5
    UNION ALL SELECT 6
    UNION ALL SELECT 7
    UNION ALL SELECT 8
    UNION ALL SELECT 9
    C'est fou! Le code devient
    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
    SELECT tab1.date_creation, tab2.nombre FROM
    (
    SELECT adddate( '2011-08-01', numlist.id ) AS date_creation
    FROM (
    SELECT a.i + b.i *10 + c.i *100 AS id
    FROM (SELECT 0 as a UNION all SELECT 1 UNION all SELECT 2 UNION all SELECT 3 UNION all SELECT 4 UNION all SELECT 5 UNION all SELECT 6 UNION all SELECT 7 UNION all SELECT 8 UNION all SELECT 9) a
    CROSS JOIN (SELECT 0 as a UNION all SELECT 1 UNION all SELECT 2 UNION all SELECT 3 UNION all SELECT 4 UNION all SELECT 5 UNION all SELECT 6 UNION all SELECT 7 UNION all SELECT 8 UNION all SELECT 9) AS b
    CROSS JOIN (SELECT 0 as a UNION all SELECT 1 UNION all SELECT 2 UNION all SELECT 3 UNION all SELECT 4 UNION all SELECT 5 UNION all SELECT 6 UNION all SELECT 7 UNION all SELECT 8 UNION all SELECT 9) AS c
    ) AS numlist
    WHERE adddate( '2011-08-01', numlist.id ) <= '2011-08-31') tab1
     
    LEFT JOIN
    (SELECT date_creation, COUNT(id) AS nombre FROM clients
    WHERE date_creation BETWEEN '2011-08-01' AND '2011-08-31' 
    GROUP BY date_creation
    ORDER BY date_creation ASC
    ) AS tab2
    ON tab1.date_creation=tab2.date_creation
    La différence entre deux dates dans cette exemple ne peux dépasser 999 jours, il faut rajouter d'autres cross join si la différence peut etre plus grande.

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 19
    Par défaut Merci à tous
    vos réponses sont très instructives, merci

    j'ai testé les 3 requêtes, elles ne renvoient aucune erreur mais des NULL pour nombre (d'inscrits) pour toutes les dates (sauf le 3 août à vrai dire)
    hors un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select id,nom from clients WHERE datetime_creation BETWEEN '2011-08-01' AND '2011-08-31'
    me renvoie bien des inscriptions

    je ne comprends pas d'où ça vient
    Merci à tous

Discussions similaires

  1. Réponses: 4
    Dernier message: 19/06/2014, 17h11
  2. Requête avec Group By utilisation clause where
    Par gcvoiron dans le forum Requêtes
    Réponses: 2
    Dernier message: 27/03/2011, 19h32
  3. Count avec clause Where
    Par bletz dans le forum Designer
    Réponses: 1
    Dernier message: 26/08/2008, 10h44
  4. Count avec clause where multi table
    Par james_kirk dans le forum Langage SQL
    Réponses: 4
    Dernier message: 01/01/2008, 17h35
  5. Petit souci avec clause where
    Par ybruant dans le forum SQL
    Réponses: 1
    Dernier message: 21/07/2005, 22h10

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