Как решить ORA-00937: не групповая функция одной группы при расчете процента? - PullRequest
6 голосов
/ 28 января 2010

Я пытаюсь получить процент от предмета, доступного в определенной области. Используя мой запрос, я получаю ошибку ORA-00937: not a single-group group function

Все детали:

У меня есть две таблицы:

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

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

и хотите получить такой результат:

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

Мой запрос:

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

Ошибка:

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

Когда я запускаю точно такой же запрос в SQL Server, он работает нормально. Как мне это исправить в Oracle?

Ответы [ 4 ]

9 голосов
/ 28 января 2010

Аналитик - ваш друг:

SELECT DISTINCT
       areas
      ,COUNT(currentitems.itemid)
       OVER (PARTITION BY areas) * 100
       / COUNT(*) OVER () Percentage
FROM allitems, currentitems
WHERE allitems.itemid = currentitems.itemid(+);
4 голосов
/ 28 января 2010

Просто, черт возьми, способ сделать это без аналитики.

Решению Джеффри требовалось DISTINCT из-за дублирования areas. Таблица allitems на самом деле является таблицей пересечения между currentitems и предполагаемой таблицей areas. В следующем запросе это представлено встроенным представлением ai. Существует еще одно встроенное представление tot, которое дает нам общее количество записей в allitems. Это количество должно быть включено в предложение GROUP BY, поскольку оно не является агрегирующим проектором.

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>

Я не знаю, будет ли этот подход работать лучше, чем решение Джеффри: вполне вероятно, что он будет работать хуже (аналитический запрос, безусловно, имеет меньше последовательных запросов) Это интересно просто потому, что освещает проблемы более четко.

1 голос
/ 28 января 2010

Небольшое изменение вашего исходного запроса:

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
1 голос
/ 28 января 2010

Вот первый быстрый проход:

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

Кроме того, в ваших тестовых данных ваш itemid 4 должен быть изменен на запад.

...