2010-01-27 7 views
5

J'essaie d'obtenir un pourcentage de l'itemid qui est disponible dans une certaine zone. En utilisant ma requête, je reçois une erreur ORA-00937: not a single-group group functionComment résoudre ORA-00937: pas une fonction de groupe à groupe unique lors du calcul du pourcentage?

Tous les détails:

Je ces deux tableaux:

ALLITEMS 
--------------- 
ItemId | Areas 
--------------- 
1  | EAST 
2  | EAST 
3  | SOUTH 
4  | WEST 

CURRENTITEMS 
--------------- 
ItemId 
--------------- 
1 
2 
3 

et veulent ce résultat:

--------------- 
Areas| Percentage 
--------------- 
EAST | 50 --because ItemId 1 and 2 are in currentitems, so 2 items divided by the total 4 in allitems = .5 
SOUTH | 25 --because there is 1 item in currentitems table that are in area SOUTH (so 1/4=.25) 
WEST | 0 --because there are no items in currentitems that are in area WEST 

ddl:

drop table allitems; 
drop table currentitems; 

Create Table Allitems(ItemId Int,areas Varchar2(20)); 
Create Table Currentitems(ItemId Int); 
Insert Into Allitems(Itemid,Areas) Values(1,'east'); 
Insert Into Allitems(ItemId,areas) Values(2,'east'); 
insert into allitems(ItemId,areas) values(3,'south'); 
insert into allitems(ItemId,areas) values(4,'east'); 

Insert Into Currentitems(ItemId) Values(1); 
Insert Into Currentitems(ItemId) Values(2); 
Insert Into Currentitems(ItemId) Values(3); 

Ma Recherche:

Select 
areas, 
(
Select 
Count(Currentitems.ItemId)*100/(Select Count(ItemId) From allitems inner_allitems Where inner_allitems.areas = outer_allitems.areas) 
From 
Allitems Inner_Allitems Left Join Currentitems On (Currentitems.Itemid = Inner_Allitems.Itemid) 
Where inner_allitems.areas = outer_allitems.areas 
***group by inner_allitems.areas*** 
***it worked by adding the above group by*** 
) "Percentage Result" 
From 
allitems outer_allitems 
Group By 
areas 

L'erreur:

Error at Command Line:81 Column:41 (which is the part `(Select Count(ItemId) From allitems inner_allitems Where inner_allitems.areas = outer_allitems.areas)`) 
Error report: 
SQL Error: ORA-00937: not a single-group group function 

Quand je lance la même requête exacte dans SQL Server, il fonctionne très bien. Comment résoudre ce problème dans Oracle?

+0

Merci pour les bonnes réponses. Différentes façons de le faire! Merci. J'ai aussi trouvé qu'en ajoutant un groupe (édité la question, regardez dans Ma Requête pour "***") ça marche aussi. – Liao

Répondre

7

Analytics sont vos amis:

SELECT DISTINCT 
     areas 
     ,COUNT(currentitems.itemid) 
     OVER (PARTITION BY areas) * 100 
    /COUNT(*) OVER() Percentage 
FROM allitems, currentitems 
WHERE allitems.itemid = currentitems.itemid(+); 
+1

Il mentionne SQL Server et Oracle, peut-être que la requête doit être portable, c'est-à-dire agnostique. –

+3

portabilité shmortability :) –

1

Voici un premier passage rapide:

select ai.areas, 
     (sum(cnt)/max(tot)) * 100 "Percentage Result" 
    from (select ai.itemid, 
       ai.areas, 
       count(ci.itemid) cnt, 
       count(ai.areas) over() tot 
      from allitems ai 
       left outer join 
       currentitems ci on (ai.itemid = ci.itemid) 
     group by ai.itemid, ai.areas 
     ) ai 
group by ai.areas 

En outre, dans vos données de test vos itemid 4 doit être changé à l'ouest.

1

Une légère modification de votre requête initiale:

Select 
areas, 
(
Select 
Count(*) 
From 
Allitems Inner_Allitems Left Join Currentitems On (Currentitems.Itemid = Inner_Allitems.Itemid) 
Where inner_allitems.areas = outer_allitems.areas 
) *100/(Select Count(*) From allitems) as percentage 
From allitems outer_allitems 
Group By areas 
3

Juste pour le plaisir de le faire, une façon de le faire sans analyse.

La solution de Jeffrey nécessitait un DISTINCT en raison de la duplication de areas. La table allitems est en fait une table d'intersection entre currentitems et une table putative areas. Dans la requête suivante, ceci est représenté par la vue en ligne ai. Il y a une autre vue en ligne tot qui nous donne le nombre total d'enregistrements dans allitems. Ce nombre doit être inclus dans la clause GROUP BY, car il ne s'agit pas d'un projecteur d'agrégation.

SQL> select ai.areas 
    2   , (count(currentitems.itemid)/tot.cnt) * 100 as "%" 
    3 from 
    4  (select count(*) as cnt from allitems) tot 
    5  , (select distinct areas as areas from allitems) ai 
    6  , currentitems 
    7  , allitems 
    8 where allitems.areas = ai.areas 
    9 and allitems.itemid = currentitems.itemid(+) 
10 group by ai.areas, tot.cnt 
11/

AREAS       % 
-------------------- ---------- 
east       50 
south      25 
west       0 

SQL> 

Je ne sais pas si cette approche de meilleurs résultats que la solution de Jeffrey: il peut tout à fait se produira pire (la requête d'analyse a certainement moins cohérente se). C'est intéressant simplement parce que cela fait ressortir les problèmes plus clairement.

+1

Néanmoins, merci pour votre contribution. Je n'ai pas eu le temps aujourd'hui, mais je vais tester toutes les bonnes réponses demain! – Liao

Questions connexes