2010-01-27 4 views
5

Próbuję uzyskać procent elementu itemid, które są dostępne w określonym obszarze. Korzystanie moje zapytanie, pojawia się błąd ORA-00937: not a single-group group functionJak rozwiązać ORA-00937: nie funkcja grupy pojedynczej grupy podczas obliczania procentu?

Wszystkie szczegóły:

mam te dwie tabele:

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

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

i chcą ten wynik:

--------------- 
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); 

moje pytanie:

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 

Błąd:

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 

Kiedy biegnę dokładnie to samo zapytanie w SQL Server, to działa dobrze. Jak to naprawić w Oracle?

+0

Dzięki za świetne odpowiedzi. Różne sposoby na zrobienie tego! Dzięki. Odkryłem też, że dodając grupę przez (edytowałem pytanie, spójrz w "Moje zapytanie" na "***"), to też działa. – Liao

Odpowiedz

7

Analytics jest twoim przyjacielem:

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

Wspomina o SQL Server i Oracle, być może zapytanie musi być przenośne, czyli agnostyczne dla producenta. –

+3

przenośność przenośności :) –

1

Oto szybki pierwszy przebieg:

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 

Również w danych testowych Twój ItemID 4 musi zostać zmieniona na zachodzie.

1

Nieznaczna modyfikacja oryginalnego zapytania:

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

Tylko do cholery, to sposób robi to bez Analytics.

Rozwiązanie firmy Jeffrey wymagało WYRÓŻNIENIA z powodu powielenia areas. Tabela allitems jest w rzeczywistości tabelą przecięć między tabelą currentitems a przypuszczalną tabelą. W poniższym zapytaniu jest to reprezentowane przez widok liniowy ai. Jest jeszcze jeden widok śródlądowy tot, który daje nam całkowitą liczbę rekordów w allitems. Ta liczba musi być zawarta w klauzuli GROUP BY, ponieważ nie jest to projektor agregujący.

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> 

Nie wiem, czy to podejście będzie działać lepiej niż rozwiązania Jeffreya: to całkiem możliwe wykona gorzej (kwerenda analityki pewno ma mniej spójne dostaje). Jest to interesujące, ponieważ uwydatnia sprawy bardziej wyraźnie.

+1

Niemniej jednak, dziękuję za wejście. Nie dostałem dzisiaj czasu, ale jutro będę testować wszystkie wspaniałe odpowiedzi! – Liao