Aller au contenu

[RESOLU] [SQL] Plusieurs count dans une seule requête


djems54

Messages recommandés

Bonjour,

J'ai une table qui gère des tickets. Chaque ticket a une date de création (champ created) et une date de fermeture (champ closed).

J'aimerai faire une requête me permettant d'afficher par jours, le nombre de tickets qui ont été créé, et le nombre qui ont été fermé.

Je sais le faire en 2 requêtes. Est-ce possible de combiner les 2 en une seule et même requête ? pour avoir les 2 résultats en 1 seul.

Lien vers le commentaire
Partager sur d’autres sites

Alors oui c'est possible, mais fort peu logique.

En gros tu as deux ensembles distincts et tu veux savoir combien de résultats tu as dans chaque ensemble. En théorie une requête sql sert à récupérer des données plus ou moins étendues se rapportant à un seul ensemble, donc si tu as plusieurs ensembles il faut faire deux requêtes.

Explication avec la requête :

select count(t1.created), count(t2.closed) from tickets as t1, tickets as t2 where t1.created='X' ans t2.created='Y'

(Non je fais pas le tri par jour, c'est pas le but). Comme tu peux le constater il n'existe aucune liaison entre les deux tables, pas de jointures, les deux tables de bases sont donc complètement séparés. Ca revient donc au même de faire une ou deux requête, mais ton code sera plus claire et plus simple à lire si il y a 2 requêtes et puis c'est une bonne habitude à prendre, les requêtes sql tarabiscotées, limite incompréhensibles, c'est une plaie dans un projet et en plus ça n'apporte rien...

Lien vers le commentaire
Partager sur d’autres sites

Voici mes 2 requêtes :

SELECT DAY(created) AS d_created, MONTH(created) AS m_created, YEAR(created) AS y_created, count(*) AS nb_created
FROM ticket
GROUP BY YEAR(created), MONTH(created), DAY(created);

SELECT DAY(closed) AS d_closed, MONTH(closed) AS m_closed, YEAR(closed) AS y_closed, count(*) AS nb_closed
FROM ticket
WHERE status="closed"
GROUP BY YEAR(closed), MONTH(closed), DAY(closed);

Qui me donne des résultats sous la forme :

d_closed	m_closed	y_closed	nb_closed
19		4		2011		1
21		4		2011		2
28		4		2011		1
29		4		2011		1
2		5		2011		3
3		5		2011		4

Même chose avec nb_created. J'aimerai avoir les 2 colonnes nb_created et nb_closed sur le même résultat.

J'ai essayé la solution de Fuinril :

SELECT count(t1.created), count(t2.closed) 
FROM ticket AS t1, ticket AS t2 
WHERE 
t1.created BETWEEN "2011-04-29 00:00:00" AND "2011-04-29 23:59:59"
AND
t2.closed BETWEEN "2011-04-29 00:00:00" AND "2011-04-29 23:59:59"
AND 
t2.status="closed"

qui me donne un résultat de 2 et 2. Alors que le 29-04 il n'y en a qu'un seul de fermé...

Lien vers le commentaire
Partager sur d’autres sites

Ah mais non ! Faut pas faire comme ça pour ce genre de requête.

Après vérification mon exemple ne fonctionne pas, le moteur de mysql traite la requête de façon bizzare (il considère que les deux tables sont identiques et agit donc comme si il n'y en avait qu'une seule, même en essayant de le faire passer par des sous-requêtes...). J'aurai du vérifier avant, mais bon c'est de toutes façons clairement pas fait pour ça.

Toujours est-il que tu veux 2 réponses (une réponse par ensemble), donc 2 lignes. Après le trier en plus par nombre de jours.... Sais pas faudrait voir si avec une clause en plus dans le group by...

Essaye ça :

SELECT count(status), status
FROM ticket as t1
WHERE 
(created BETWEEN "2011-04-29 00:00:00" AND "2011-04-29 23:59:59" and status = 'open') or 
( closed BETWEEN "2011-04-29 00:00:00" AND "2011-04-29 23:59:59" and status = 'closed') group by status

Lien vers le commentaire
Partager sur d’autres sites

Le résultat est :

Expr1   status
2       closed

Sachant que dans ce cas précis (du 29-04), il y a 2 tickets créés, et 1 fermé.

Ensuite, dans l'idéal, il faudrait que l'on ait pas besoin de rentrer une date précise, comme dans les 2 premières requêtes.

Lien vers le commentaire
Partager sur d’autres sites

Pour avoir testé (cette fois ci) la requête, je peux t'assurer qu'elle fonctionne.

Après a toi de voir si le status d'un ticket ouvert est bien renseigné à open, sinon mets autre chose (genre t1.status is NULL ou t1.status='')...

Pour ta question, une requête du genre devrait convenir

SELECT day, month, year, count(status), status
FROM test as t1
group by DATE(created), DATE(closed), status

C'est certainement pas parfait mais je doute que quelqu'un puisse faire mieux sans connaitre la structure de la table (qui m'a l'air ma foi particulière).

En gros tu auras 2 lignes par jour avec le nombre de tickets fermés/ouverts.

Lien vers le commentaire
Partager sur d’autres sites

Hello !

Faire un bête "UNION" de tes deux requêtes ne répond pas à ton problème ?

SELECT DAY(created) AS day, MONTH(created) AS month, YEAR(created) AS year, count(*) AS nb, 'created' AS status
FROM ticket
GROUP BY YEAR(created), MONTH(created), DAY(created);
UNION
SELECT DAY(closed) AS day, MONTH(closed) AS month, YEAR(closed) AS year, count(*) AS nb, 'closed' AS status
FROM ticket
WHERE status='closed'
GROUP BY YEAR(closed), MONTH(closed), DAY(closed);

Un truc du genre (je n'ai pas testé :transpi:)...

Lien vers le commentaire
Partager sur d’autres sites

la syntaxe que tu cherche est du genre:

SELECT req1.nbouverts, req2.nbfermé FROM

(SELECT count(ouverts) as nbouverts FROM tatable) as req1, <- Jointure naturelle

(SELECT count(fermé) as nbfermé FROM tatable) as req2);

enfin si j'ai bien compris ce que tu demande, j'ai eu recemment à faire une requete du genre et je m'en suis sorti comme ca

Lien vers le commentaire
Partager sur d’autres sites

Étant donné que ton champ status est vraisemblablement de type VARCHAR, il n'y a pas d'autre choix que d'utiliser deux requêtes distinctes ou deux sous-requêtes jointes par une UNION. Pour une seule requête je ne vois pas de cas où tu peux utiliser plusieurs fonctions d'agrégat où ces dernières doivent s'appliquer sur des enregistrements différents.

Par contre, il reste possible de répondre à ton problème en une requête propre sous deux conditions : que ton champ status ne puisse avoir que 2 états possibles, et ton moteur de base de données fonctionne avec les valeurs booléennes de la même façon que MySQL. Si tel est effectivement le cas, et que tu as le contrôle sur le schéma de ta table, tu pourrais remplacer ce champ. Tu peux aussi, de manière transitoire, le garder. Pour la suite en tout cas, ajoute le champ suivant : `isClosed` TINYINT NOT NULL DEFAULT FALSE.

Avec des valeurs correctes en table (les champs pour lequels status='closed' ont aussi isClosed=TRUE), la requête suivante devrait alors marcher :

SELECT DAY(created) AS d_created, MONTH(created) AS m_created, YEAR(created) AS y_created, COUNT(*) AS nb_created, SUM(isClosed) AS nb_closed
FROM ticket
GROUP BY y_created, m_created, d_created;

Lien vers le commentaire
Partager sur d’autres sites

Cela te sera probablement inutile car non implementé en mySQL, mais au cas ou tu sois sur un autre SGBD plus complet, je pense que tu devrai regarder du côté des WINDOW/PARTITION BY qui permettent de faire exactement ce que tu veux sans jongler avec des unions, requêtes imbriquées ou autres workaround à base de tables imbriquées.

http://elegantcode.com/2009/01/04/sql-window-clause/

http://www.postgresql.org/docs/8.4/interactive/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS

http://www.postgresql.org/docs/current/static/tutorial-window.html

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...