Précédent   Forum des professionnels en informatique > Bases de données > MS SQL-Server > Développement
Développement Forum d'entraide sur le Transact-SQL, le CLR, les procédures stockées, les triggers, les requêtes SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 14/06/2011, 11h12   #1
Invité régulier
 
Inscription : mars 2009
Messages : 25
Détails du profil
Informations forums :
Inscription : mars 2009
Messages : 25
Points : 7
Points : 7
Par défaut Construire un intervalle dans une requête sql server

Bonjour, ma requête sql est la suivante :

SELECT nb_cmd, count(*) as nb_clients

FROM (
SELECT ID_CLIENT, count(*) as nb_cmd
FROM TableCmd (NOLOCK)
WHERE DATE is null
GROUP BY ID_CLIENT
) t

GROUP BY nb_cmd;

Le résultat me donne le nombre de clients correspondant à un nombre de commandes :
Citation:
Nb_cmd Nb_client
1 19515
2 845
3 149
4 71
5 36
6 26
7 12
8 12
9 7
10 3
11 3
12 2
13 1
15 2
Jusqu'ici tout va bien !

Ce que j'essaye de faire c'est de regrouper ces données en intervalle, car le résultat est vraiment trop grand. Ceci est dans le but de représenter à l'aide d'un graphe la répartition du nbr de client par commande.

Je n'arrive pas à formuler ce problème!
Merci d'avance pour toute aide proposée !
Marsupilami23 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/06/2011, 11h35   #2
Modérateur

 
Avatar de elsuket
 
Homme Nicolas Souquet
Administrateur de base de données
Inscription : janvier 2005
Messages : 4 669
Détails du profil
Informations personnelles :
Nom : Homme Nicolas Souquet
Âge : 30
Localisation : Thaïlande

Informations professionnelles :
Activité : Administrateur de base de données
Secteur : High Tech - Éditeur de logiciels

Informations forums :
Inscription : janvier 2005
Messages : 4 669
Points : 8 729
Points : 8 729
Bonjour,

Vous pouvez faire comme suit si vous êtes sous SQL Server 2005 ou + :

Code :
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
WITH
	INTERVALLE AS
	(
		SELECT	0 AS low_bound, 1 AS high_bound
		UNION ALL SELECT 1, 5
		UNION ALL SELECT 5, 10
		UNION ALL SELECT 10, 50
		UNION ALL SELECT 50, 100
		UNION ALL SELECT 100, 200
		UNION ALL SELECT 200, 1000
		UNION ALL SELECT 1000, 100000
	)
	, COMMANDE AS
	(
		SELECT ID_CLIENT
			, COUNT(*) AS nb_cmd
		FROM	dbo.TableCmd
		WHERE	DATE IS NULL
		GROUP	BY ID_CLIENT
	)
SELECT		I.low_bound
		, I.high_bound
		, COUNT(*) AS nb_clients
FROM		INTERVALLE AS I
INNER JOIN	COMMANDE AS C
			ON C.nb_cmd > I.low_bound
			AND C.nb_cmd <= high_bound
GROUP BY	I.low_bound, I.high_bound
ORDER BY	I.low_bound, I.high_bound
Et dès SQL Server 2000 :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SELECT		I.low_bound
		, I.high_bound
		, COUNT(*) AS nb_clients
FROM		(
			SELECT	0 AS low_bound, 1 AS high_bound
			UNION ALL SELECT 1, 5
			UNION ALL SELECT 5, 10
			UNION ALL SELECT 10, 50
			UNION ALL SELECT 50, 100
			UNION ALL SELECT 100, 200
			UNION ALL SELECT 200, 1000
			UNION ALL SELECT 1000, 100000
		) AS I
INNER JOIN	(
			SELECT ID_CLIENT
				, COUNT(*) AS nb_cmd
			FROM	dbo.TableCmd
			WHERE	DATE IS NULL
			GROUP	BY ID_CLIENT
		) AS C
			ON C.nb_cmd > I.low_bound
			AND C.nb_cmd <= high_bound
GROUP BY	I.low_bound, I.high_bound
ORDER BY	I.low_bound, I.high_bound
@++
__________________
En bases de données relationnelles SQL, il n'y a ni tableaux, ni enregistrements, ni champs: il y a des tables, des lignes et des colonnes.
Blog | Profil| Consulter ou télécharger les fichiers d'aide de SQL Server, des versions 2000 à 2012
elsuket est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 14/06/2011, 11h54   #3
Invité régulier
 
Inscription : mars 2009
Messages : 25
Détails du profil
Informations forums :
Inscription : mars 2009
Messages : 25
Points : 7
Points : 7
Re,

Merci beaucoup pour votre aide elsuket!
J'ai exécute votre code et ça à l'air de vraiment marcher !

J'essaye de comprendre la façon avec laquelle vous avez construit votre solution, en tous les cas merci beaucoup !
Marsupilami23 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 14/06/2011, 11h55   #4
Membre Expert
 
Inscription : janvier 2010
Messages : 1 084
Détails du profil
Informations personnelles :
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : janvier 2010
Messages : 1 084
Points : 1 573
Points : 1 573
Bonjour

Si votre intervalle est linéaire (tranche de 10 dans mon exemple) et à partir de 2005, vous pouvez aussi faire comme ceci :

Code SQL :
1
2
3
4
5
6
7
 
SELECT 
    COUNT(*) / 10 * 10 AS BorneInf,
    COUNT(*) / 10 * 10 + 9 BorneSup,
    COUNT(*) OVER (PARTITION BY COUNT(*) / 10) AS NbClient
FROM TableCmd
GROUP BY IDClient

Par contre, si une tranche n'est aucun client, elle n'apparaitra pas dans le resultat...
aieeeuuuuu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/06/2011, 11h25   #5
Invité régulier
 
Inscription : mars 2009
Messages : 25
Détails du profil
Informations forums :
Inscription : mars 2009
Messages : 25
Points : 7
Points : 7
Merci aieeeuuuuu pour votre réponse, j'ai essayé d'adapter votre code avec mes données mais je n'ai pas réussi. Etant donné que la première solution marche , je garde la première proposition.
Par contre je n'ai pas très bien compris votre logique, je vais essayer d'y penser prochainement.

En tout cas merci !
Marsupilami23 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/06/2011, 11h38   #6
Membre Expert
 
Inscription : janvier 2010
Messages : 1 084
Détails du profil
Informations personnelles :
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : janvier 2010
Messages : 1 084
Points : 1 573
Points : 1 573
ce n'est pas bien compliqué :

COUNT() renvoi un entier. Si vous le divisez, vous gardez un entier, et donc uniquement la partie entière du résultat de la division.

Ainsi (et toujours dans un contexte de INT ):

si @x est valué à 18 :
@x /10 = 1

si @x vaut 13 :
@x /10 = 1

donc en partitionnant sur COUNT(*) /10, on regroupe par tranche de 10...

Vous pouvez aussi utiliser la fonction ROUND() pour arrondir explicitement et rendre la requête peut être plus compréhensible
aieeeuuuuu est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/06/2011, 11h45   #7
Invité régulier
 
Inscription : mars 2009
Messages : 25
Détails du profil
Informations forums :
Inscription : mars 2009
Messages : 25
Points : 7
Points : 7
Citation:
Envoyé par aieeeuuuuu Voir le message
ce n'est pas bien compliqué :

COUNT() renvoi un entier. Si vous le divisez, vous gardez un entier, et donc uniquement la partie entière du résultat de la division.

Ainsi (et toujours dans un contexte de INT ):

si @x est valué à 18 :
@x /10 = 1

si @x vaut 13 :
@x /10 = 1

donc en partitionnant sur COUNT(*) /10, on regroupe par tranche de 10...

Vous pouvez aussi utiliser la fonction ROUND() pour arrondir explicitement et rendre la requête peut être plus compréhensible


D'accord, donc si je comprend bien les bornes de l'intervalle à construire sont définies à partir du nombre d'enregistrement contenus dans ma table.

J'y vois plus clair en tout cas !
Je vais l'essayer , Merci
Marsupilami23 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 15/06/2011, 11h52   #8
Membre Expert
 
Inscription : janvier 2010
Messages : 1 084
Détails du profil
Informations personnelles :
Localisation : France, Rhône (Rhône Alpes)

Informations forums :
Inscription : janvier 2010
Messages : 1 084
Points : 1 573
Points : 1 573
non,

C'est le dénominateur de la division du COUNT qui défini la tranche.

Vous pouvez faire PARTITION BY COUNT(*) / 100 et regrouper par tranche de 100

par contre en effet, si une tranche ne contient aucun élément, elle ne sera pas dans le resultat.

Dans votre cas, si aucun client n'a passé entre 10 et 19 commandes, vous aurez la tranche 0-9, la tranche 20-29, mais pas la tranche 10-19.
aieeeuuuuu est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 05h08.


 
 
 
 
Partenaires

Hébergement Web