2009-05-13 8 views
3

J'ai deux colonnes dans ma table Items 'Category', 'Category2', les deux colonnes contiennent essentiellement les mêmes informations. Si j'avais conçu la base de données j'aurais créé une table séparée pour les catégories et ajouté des éléments aux catégories basées hors de cette table, malheureusement je n'ai pas créé la base de données et je ne peux pas la changer maintenant mais je pense qu'il y a toujours un façon de faire ce que je veux faire.Requête SQL GROUP BY avancée

Un exemple de la table est présentée ci-dessous

Category    Category2 
------------------ ----------------- 
truck    full size - pickup 
full size - pickup truck 
Sedan    Import - Sedan 
Convertible   Domestic - Coupe 

Je veux exécuter une requête pour compter le nombre total de camions, berlines, pleine grandeur - pick-up, etc. J'ai essayé la requête ci-dessous, mais il groupé les deux colonnes séparément

SELECT Category, Count(*) as Count 
FROM Items 
GROUP BY Category, Category2 
+0

Heureux que vous au moins reconnaître e e problèmes dans la structure actuelle – HLGEM

+0

Donc, pour cet exemple, vous vous attendez à retrouver les éléments suivants: truck = 2; Pleine taille - ramassage = 2; Sedan = 1; Convertible = 1; Importation - Berline = 1; Domestique - Coupé = 1? – BIBD

+0

@CodeSlave - C'est exact, David B et Araqnid ont tous deux cloué la solution. Merci tout le monde!! – Patcouch22

Répondre

14

Juste vider les deux catégories dans une seule colonne avant le regroupement.

SELECT Category, Count(*) as TheCount 
FROM 
(
    SELECT Category1 as Category 
    FROM Items 
    UNION ALL 
    SELECT Category2 
    FROM Items 
) sub 
GROUP BY Category 
+2

Assurez-vous d'utiliser union tout comme cela montre, union donnerait la mauvaise réponse – HLGEM

1

Je suis sûr qu'il ya une meilleure façon de le faire, mais ici ya go

declare @group1 (Category1, Count int) 
declare @group2 (Category2, Count int) 

insert into @group1 (Category1, Count1) 
select Category1, count(Category1) 
from Table 
group by Category1 

insert into @group2 (Category2, Count2) 
select Category2, count(Category2) 
from Table 
group by Category2 

select 
coalesce(Category1, Category2) as Category, 
coalesce(Count1,0) + coalesce(Count2,0) as CountAll 
from @group1 a 
    full outer join @group2 b 
     on a.Category1=b.Category2 
+0

Supposons que «camion» est dans la première colonne deux fois et la deuxième colonne 20 fois. Cette réponse montre le nombre de camions comme 2, au lieu de 22. –

+0

yup, vous avez raison. Je l'ai corrigé. – DForck42

7

Imaginez qu'une ligne de « catégorie, category2 » peut être transformé en deux lignes (une avec « catégorie », une avec « category2 ») pour obtenir ce que vous voulez. Tu ferais ça comme ça:

SELECT items.category /* , other columns... */ 
FROM items 
UNION ALL 
SELECT items.category2 /* , other columns... */ 
FROM items 

donc tout ce que vous devez alors faire est globale à travers ceux-ci:

SELECT category, count(*) FROM (
    SELECT items.category FROM items 
    UNION ALL 
    SELECT items.category2 FROM items 
    ) expanded 
GROUP BY category 

Vous pouvez également faire l'ensemble par étapes comme celle-ci si votre base de données supporte:

with subcounts as (
    select items.category, items.category2, count(*) as subcount 
    from items 
    group by category, category2) 
select category, sum(subagg) as finalcount from (
    select subcounts.category, sum(subcount) as subagg from subcounts group by category 
    union all 
    select subcounts.category2, sum(subcount) as subagg from subcounts group by category2 
) combination 
group by category 

Cela limitera à un seul balayage de la table principale des articles, bon si vous avez seulement un petit nombre de catégories. Vous pouvez imiter la même chose avec des tables temporaires dans des bases de données qui ne supportent pas « AVEC ... »

EDIT:

Je suis sûr qu'il devait y avoir une autre façon de le faire sans numériser deux fois des articles et il y a. Eh bien, voici la version PostgreSQL:

SELECT category, count(*) FROM (
    SELECT CASE selector WHEN 1 THEN category WHEN 2 THEN category2 END AS category 
    FROM Items, generate_series(1,2) selector 
) items_fixed GROUP BY category 

Le seul bit spécifique-postgresql ici est "generate_series (1,2)" qui produit une "table" contenant deux un rows-- avec "1" et une avec "2". Ce qui est IMHO l'une des fonctionnalités les plus pratiques dans postgresql. Vous pouvez également implémenter des choses similaires dans SQL Server, bien sûr. Ou vous pouvez dire "(sélectionner 1 comme union de sélection tous sélectionner 2)". Une autre alternative est "(valeurs (1), (2)) série (sélecteur)" bien que la quantité de cette syntaxe est standard et combien est spécifique à postgres, je ne suis pas sûr. Ces deux approches ont l'avantage de donner au planificateur l'idée qu'il n'y aura que deux lignes.

La jointure croisée de ces éléments de table de série nous permet de générer deux lignes de sortie pour chaque ligne d'élément. Vous pouvez même prendre cette sous-requête "items_fixed" et en faire une vue - ce qui est l'inverse du processus que j'ai tendance à utiliser pour essayer de résoudre ce genre de problèmes.

+0

+1 Intéressant comment le nom par défaut d'une union vient de la première table. Bien que la variante WITH entraîne toujours deux analyses de table. – Andomar

+0

Avec quelle base de données avez-vous essayé la variante WITH? (ahem) Je l'ai testé avec la version bêta de PostgreSQL 8.4, où je comprends qu'il est fondamentalement implémenté comme une table temporaire, ce qui implique un balayage de "Items" et deux scans CTE, qui sont des scans du résultat temporaire. Ce n'est pas nécessairement une victoire. seulement si le nombre de combinaisons de catégories est significativement plus petit que le nombre d'items; mais cela semble probable. – araqnid

+0

Merci! Très informatif - a donné la réponse à David pour répondre un min plus tôt mais merci de l'expliquer! – Patcouch22

2

essayer

select category,sum(CategoryCount) 
from(
select Category1 as category, count(Category1) as CategoryCount 
from Table 
group by Category1 
union all 
select Category2 as category, count(Category2) as CategoryCount 
from Table 
group by Category2) x 
group by category 
+1

Nécessite une clause groupby en dehors de la sous-requête. –

0

essayer

select type comme 1, count (*) comme nombre de table où la catégorie comme '% taille complète - pickup%'

union

choisir le type 2, compter (*) comme le nombre à partir de la table où la catégorie comme '% truck%'

union

select type comme 3, count (*) comme nombre de table où la catégorie comme '% berline%'
et ainsi de suite ......

type 1 sera soit votre nombre count pleine grandeur de type 2 votre camion et ainsi de suite ....

espérons que cette aide

+0

pas très utile étant donné que si/quand il y avait une nouvelle catégorie, il devrait éditer la requête pour qu'elle fonctionne correctement. – DForck42

+0

il peut créer une procédure stockée avec la catégorie comme paramètre. – Eric

+0

Et appelez-le une fois pour chaque catégorie? Un peu de gaspillage, non? –