2010-07-23 8 views
4

Ma table comportait 3 champs: id et unit. Je veux compter combien d'ID ont < 10, 10-49, 50-100 unités etc. Le résultat final devrait ressembler à:SQL: aide à la requête

Category | countIds 
<10  | 1516 
10 - 49 | 710 
50 - 99 | 632 
etc. 

Ceci est la requête qui retourne chaque identifiant et le nombre d'unités qu'il a:

select id, count(unit) as numUnits 
from myTable 
group by id 

Comment puis-je construire sur cette requête pour me donner la catégorie, countIds résultat?

Note: Je n'arrivais pas à trouver comment nommer cette question. S'il vous plaît ne hésitez pas à le modifier/offre des suggestions

Répondre

3
create temporary table ranges (
    seq   int primary key, 
    range_label varchar(10), 
    lower  int, 
    upper  int 
); 

insert into ranges values 
(1, '<10',  0, 9), 
(2, '10 - 49', 10, 49), 
(3, '50 - 99', 50, 99) 
etc. 

select r.range_label, count(c.numUnits) as countIds 
from ranges as r 
join (
    select id, count(unit) as numUnits 
    from myTable 
    group by id) as c 
on c.numUnits between r.lower and r.upper 
group by r.range_label 
order by r.seq; 

modifier: somme changé() à compter() ci-dessus.

+0

Très beau, seulement r.seq doit être dans le select ne le fait pas, parce que vous l'avez dans l'ordre par (il ne fonctionne pas sur Oracle parce que tout ce que vous commandez par doit être dans le select, et je pense c'est vrai pour la plupart des DB). En tout cas, je pense vraiment que c'est une bonne réponse et mieux que la mienne! – dcp

+0

@dcp: Merci! Oui, il est possible que Oracle ou une autre implémentation nécessite qu'une colonne dans ORDER BY apparaisse dans le select. Mais FWIW, ce serait une idiosyncrasie du vendeur; il n'est pas requis par la norme ANSI SQL. J'utilise le plus souvent MySQL, et ça marche bien. –

+0

Une expression triée par doit uniquement apparaître dans la liste de sélection si vous utilisez DISTINCT ou GROUP BY, au moins dans Oracle. –

1

Donner un exemple pour une plage: (10 - 49)

select count(id) from 
(select id, count(unit) as numUnits from myTable group by id) 
where numUnits >= '10' && numUnits <= '49' 
+0

Si je comprends bien, cette réponse signifierait que je devrais écrire un requête séparée pour chaque catégorie. Je veux une requête pour le diviser en catégories. – dmr

+0

@dmr Ce serait plus simple si vous pouviez faire en sorte que les catégories aient la même taille. Vous avez une catégorie avec 10 articles et d'autres avec 40 articles. Si vous devez avoir des catégories de tailles différentes, vous allez avoir une solution compliquée. – DOK

1

Il est pas exactement ce que vous voulez, mais vous pouvez utiliser des plages fixes, comme suit:

select ' < ' || floor(id/50) * 50, count(unit) as numUnits 
    from myTable 
group by floor(id/50) * 50 
order by 1 
+0

Quatre espaces - pas de pré-tags SVP) –

2
SELECT id, countIds 
FROM (
SELECT id 
    , 'LESS_THAN_TEN' CATEGORY 
    , COUNT(unit) countIds 
    FROM table1 
GROUP BY ID 
HAVING COUNT(UNIT) < 10 
UNION ALL 
SELECT id 
    , 'BETWEEN_10_AND_49' category 
    , COUNT(unit) countIds 
    FROM table1 
GROUP BY ID 
HAVING COUNT(UNIT) BETWEEN 10 AND 49 
UNION ALL 
SELECT id 
    , 'BETWEEN_50_AND_99' category 
    , COUNT(unit) countIds 
    FROM table1 
GROUP BY id 
HAVING COUNT(UNIT) BETWEEN 50 AND 99 
) x 
+0

+1: Il suffit de le faire pivoter pour correspondre à la sortie attendue de l'OP –

+0

Oui, merci, je l'ai corrigé. – dcp

+0

En fait, je pense que Bill Karwin a une très bonne solution, car il est piloté par table, je pense que c'est le meilleur que j'ai vu à cette question. – dcp

3
select category_bucket, count(*) 
    from (select case when category < 10 then "<10" 
        when category >= 10 and category <= 49 then "10 - 49" 
        when category >= 50 and category <= 99 then "50 - 99" 
        else "100+" 
       end category_bucket, num_units 
      from my_table) 
    group by category_bucket 

Une solution groupée dynamiquement est beaucoup plus difficile.

+0

Voir la solution de Bill Karwin, c'est piloté par table et dynamique. – dcp

+0

L'ajout d'une table temporaire et le peuplement de plages, à mon avis, qualifie cela de "plus difficile". Certainement une solution plus intrusive, et on peut ne pas être en mesure d'ajouter des tables aux bases de données pour les produits fournis par le fournisseur. –

1

Essayez cet exemple de travail dans SQL Server TSQL

SET NOCOUNT ON 
GO 
WITH MyTable AS 
(
SELECT 00 as Id, 1 Value UNION ALL 
SELECT 05 , 2 UNION ALL 
SELECT 10 , 3 UNION ALL 
SELECT 15 , 1 UNION ALL 
SELECT 20 , 2 UNION ALL 
SELECT 25 , 3 UNION ALL 
SELECT 30 , 1 UNION ALL 
SELECT 35 , 2 UNION ALL 
SELECT 40 , 3 UNION ALL 
SELECT 45 , 1 UNION ALL 
SELECT 40 , 3 UNION ALL 
SELECT 45 , 1 UNION ALL 
SELECT 50 , 3 UNION ALL 
SELECT 55 , 1 UNION ALL 
SELECT 60 , 3 UNION ALL 
SELECT 65 , 1 UNION ALL 
SELECT 70 , 3 UNION ALL 
SELECT 75 , 1 UNION ALL 
SELECT 80 , 3 UNION ALL 
SELECT 85 , 1 UNION ALL 
SELECT 90 , 3 UNION ALL 
SELECT 95 , 1 UNION ALL 
SELECT 100 , 3 UNION ALL 
SELECT 105 , 1 UNION ALL 
SELECT 110 , 3 UNION ALL 
SELECT 115 , 1 Value 
) 
SELECT Category, COUNT (*) CountIds 
FROM 
(
    SELECT 
     CASE 
      WHEN Id BETWEEN 0 and 9 then '<10' 
      WHEN Id BETWEEN 10 and 49 then '10-49' 
      WHEN Id BETWEEN 50 and 99 then '50-99' 
      WHEN Id > 99    then '>99' 
     ELSE '0' END as Category  
    FROM MyTable 
) as A 
GROUP BY Category 

Cela vous donnera le résultat suivant

Category CountIds 
-------- ----------- 
<10  2 
>99  4 
10-49 10 
50-99 10