Ошибка агрегатные функции нельзя применять в конструкции group by

I am looking for clarification on this. I am writing two queries below:

We have a table of employee name with columns ID , name , salary

  1.  Select name from employee 
    where sum(salary) > 1000 ;

  2.  Select name from employee 
    where substring_index(name,' ',1) = 'nishant' ;

Query 1 doesn’t work but Query 2 does work. From my development experience, I feel the possible explanation to this is:

The sum() works on a set of values specified in the argument. Here
‘salary’ column is passed , so it must add up all the values of this
column. But inside where clause, the records are checked one by one ,
like first record 1 is checked for the test and so on. Thus
sum(salary) will not be computed as it needs access to all the column
values and then only it will return a value.

Query 2 works as substring_index() works on a single value and hence here it works on the value supplied to it.

Can you please validate my understanding.

Cœur's user avatar

Cœur

36.9k25 gold badges193 silver badges262 bronze badges

asked Feb 26, 2017 at 16:10

Nishant_Singh's user avatar

15

The reason you can’t use SUM() in the WHERE clause is the order of evaluation of clauses.

FROM tells you where to read rows from. Right as rows are read from disk to memory, they are checked for the WHERE conditions. (Actually in many cases rows that fail the WHERE clause will not even be read from disk. «Conditions» are formally known as predicates and some predicates are used — by the query execution engine — to decide which rows are read from the base tables. These are called access predicates.) As you can see, the WHERE clause is applied to each row as it is presented to the engine.

On the other hand, aggregation is done only after all rows (that verify all the predicates) have been read.

Think about this: SUM() applies ONLY to the rows that satisfy the WHERE conditions. If you put SUM() in the WHERE clause, you are asking for circular logic. Does a new row pass the WHERE clause? How would I know? If it will pass, then I must include it in the SUM, but if not, it should not be included in the SUM. So how do I even evaluate the SUM condition?

answered Feb 26, 2017 at 16:53

2

Why can’t we use aggregate function in where clause

Aggregate functions work on sets of data. A WHERE clause doesn’t have access to entire set, but only to the row that it is currently working on.

You can of course use HAVING clause:

select name from employee 
group by name having sum(salary) > 1000;

If you must use WHERE, you can use a subquery:

select name from (
    select name, sum(salary) total_salary from employee
    group by name
) t where total_salary > 1000;

answered Feb 26, 2017 at 16:40

Gurwinder Singh's user avatar

Gurwinder SinghGurwinder Singh

38.3k6 gold badges51 silver badges76 bronze badges

0

sum() is an aggregation function. In general, you would expect it to work with group by. Hence, your first query is missing a group by. In a group by query, having is used for filtering after the aggregation:

Select name
from employee 
group by name
having sum(salary) > 1000 ;

Aaron Golliver's user avatar

answered Feb 26, 2017 at 16:14

Gordon Linoff's user avatar

Gordon LinoffGordon Linoff

1.2m57 gold badges639 silver badges781 bronze badges

0

Using having works since the query goes direct to the rows in that column while where fails since the query keep looping back and forth whenever conditions is not met.

answered Mar 5, 2020 at 12:06

Paul Kiarie's user avatar

У меня возникла следующая странная проблема с запросом Sqlite в устройствах версии 4.4.2 на Android 4.4.

Структура таблицы следующая:

CREATE TABLE responsemaster (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    formid integer,
    proposerid text,
    fieldid integer,
    response text,
    remarks text,
    listId integer,
    isMarked integer
)

и запрос, который дает ошибку,

SELECT id as id, formid as formid, proposerid as proposerid, MIN(fieldid) fieldid, response as response, remarks as remarks, listId as listId, isMarked as isMarked
FROM responsemaster
WHERE formid = 40066 AND proposerid = '7ca6533a-c5f0-43e2-9980-83f9ae2c7370201802230113550000'
GROUP BY fieldid

Исключением я получаю следующее

android.database.sqlite.SQLiteException: aggregate functions are not allowed in the GROUP BY clause (code 1):, 
while compiling: SELECT id as id, formid as formid, proposerid as proposerid,  **MIN(CAST(fieldid AS INTEGER)) AS fieldid**, response as response, remarks as remarks, listId as listId, isMarked as isMarked FROM responsemaster WHERE formid = 40066 AND proposerid = '7ca6533a-c5f0-43e2-9980-83f9ae2c7370201802230113550000'  GROUP BY fieldid

Вышеприведенный запрос будет успешно выполнен в браузере SQLite и в устройствах с расширенными версиями Android 4.4.2. Пожалуйста, может кто-нибудь помочь мне, как я могу исправить эту ошибку?

этот код sql выдает

агрегатные функции не допускаются в WHERE

SELECT o.ID ,  count(p.CAT)
FROM Orders o
INNER JOIN Products p ON o.P_ID = p.P_ID 
WHERE count(p.CAT) > 3
GROUP BY o.ID;

Как избежать этой ошибки?

3 ответов


заменить WHERE п. с HAVING, например:

SELECT o.ID ,  count(p.CAT)
FROM Orders o
INNER JOIN Products p ON o.P_ID = p.P_ID 
GROUP BY o.ID
HAVING count(p.CAT) > 3;

HAVING похож на WHERE, то есть оба используются для фильтрации результирующих записей, но HAVING используется для фильтрации агрегированных данных (при GROUP BY используется).


использовать HAVING пункт вместо WHERE

попробуйте это:

SELECT o.ID, COUNT(p.CAT) cnt
FROM Orders o
INNER JOIN Products p ON o.P_ID = p.P_ID 
GROUP BY o.ID HAVING cnt > 3

будет ли self join идти на бросок с join, где у нас есть условие для перечисления цен, которые больше медианы цен, перечисленных в таблице order?

например. order_item, Order_Price

поскольку агрегатные функции нельзя использовать в предложении WHERE >

select a.order_item_product_price, count(distinct 
a.order_item_product_price) from 
default.order_items a , default.order_items b
where a.order_item_product_price = b.order_item_product_price
group by a.order_item_product_price
having a.order_item_product_price > appx_median(b.order_item_product_price)
order by a.order_item_product_price limit 10

У меня есть следующие данные:

table: identifier

objectid    type    name            value
9345783451  GUID    msisdn          bc3b2286379da25fd6ef3bac120827589c783
9345783451  UMID    umid            f701a99c-96c9-4d4a-8508-932eeeaca77c
9345783451  UMDID   umdid           2840f267-4bdd-4af4-8b36-72badbce1e11
9345783451  UMDID   umdid           bbe467f5-0fc4-4624-8b01-dd656767d3b2
9345783451  GUID    encrypted       ZPmBF2Spq8DBX0wl
9345783451  UMDID   umdid           a4c6b3cb-938f-4ae5-8246-f2612ffd946b
9345783451  UMDID   umdid           2a8e5f98-5a74-431e-bbaf-7c75fdeb991a
9345783451  UMDID   umdid           269a39b9-1122-4d08-9ca4-36f6c8e00e8e
9345783451  COOKIE  amcv            39852788960115122553605179944081330813
9345783451  UMDID   umdid           7715969f-63ab-4540-952c-73beafb46024
9345783451  GROUPID ban-sha2        1d98f855e9a4fbeba1937f774b6dbab2ca194b5
9345783451  COOKIE  token           21agqB6x_H8.1575825731298.aXHr4GoVupopE
9345783451  GUID    acn             12433792
9345783451  UMDID   umdid           f2cf7402-21d2-44ea-b432-66e997cfebbf
9345783451  GUID    targetId        1255625699
9345783451  UMDID   umdid           b8d55cdd-4a95-4e07-8eeb-f281a0961a6a
9345783451  UMDID   umdid           af890608-b512-4a96-9274-f39f388ff442
9345783451  UMDID   umdid           0c55ecb1-e24e-419d-97a1-48f6eba45fe0

Затем я делаю следующий запрос:

select objectid,
           count(objectid) filter ( where type = 'GUID' )                                                                     as guid_count,
           count(objectid) filter ( where type = 'GUID' and (name in
                                                             ('acn', 'encrypted', 'kdid', 'msisdn', 'targetId')) ) as cuid_count,
           count(objectid) filter ( where name = 'umdid' )                                                                    as umdid_count
    from identifier
    where objectid = '9345783451'
    group by objectid;

Результат верный:

objectid    guid_count cuid_count umdid_count
9345783451  4          3          10

Затем я добавляю два столбца, имя и значение:

select objectid,
               count(objectid) filter ( where type = 'GUID' )                                                                     as guid_count,
               count(objectid) filter ( where type = 'GUID' and (name in
                                                                 ('acn', 'encrypted', 'kdid', 'msisdn', 'targetId')) ) as cuid_count,
               count(objectid) filter ( where name = 'umdid' )                                                                    as umdid_count,
               case
                   when identifier.name = 'acn' then identifier.value::text
                   else '' end                                                                                                                          as acn
        from identifier
        where objectid = '9345783451'
        group by objectid, name, value;

Это возвращение:

objectid   guid_count cuid_count umdid_count acn
9345783451  0          0         1           "" 
9345783451  1          0         0           "" 
9345783451  0          0         1           "" 
9345783451  0          0         0           "" 
9345783451  0          0         1           "" 
9345783451  1          1         0           12433792 
9345783451  0          0         1           "" 
9345783451  0          0         1           "" 
9345783451  1          1         0           "" 
9345783451  0          0         0           "" 
9345783451  0          0         1           "" 
9345783451  0          0         1           "" 
9345783451  0          0         0           "" 
9345783451  0          0         1           "" 
9345783451  0          0         1           "" 
9345783451  0          0         0           "" 
9345783451  1          1         0           "" 
9345783451  0          0         1           ""

"" empty string

Я ожидаю:

objectid    guid_count cuid_count umdid_count acn
9345783451  4          3          10          12433792

Если я добавлю группу по guid_count, cuid_count и umdid_count:

[42803] ERROR: aggregate functions are not allowed in GROUP BY Position: 26

Как преодолеть эту проблему? Не могли бы вы указать мне, где моя ошибка?

Спасибо.

1 ответ

Лучший ответ

Вы должны использовать агрегат для добавленного столбца, например:

select objectid,
    count(objectid) filter ( where type = 'GUID' ) as guid_count,
    count(objectid) filter ( 
        where type = 'GUID' 
        and (name in ('acn', 'encrypted', 'kdid', 'msisdn', 'targetId')) 
        ) as cuid_count,
    count(objectid) filter ( where name = 'umdid' ) as umdid_count,
    max(case
        when identifier.name = 'acn' then identifier.value::text
        else '' end) as acn
from identifier
where objectid = '9345783451'
group by objectid;


1

klin
16 Дек 2019 в 20:01

В SQL имеется множество предопределенных агрегатных функций, которые можно использовать для написания запросов для получения именно такой информации. Предложение GROUP BY указывает, как группировать строки из таблицы данных при агрегировании информации, тогда как предложение HAVING отфильтровывает строки, которые не принадлежат указанные группы.

Агрегатные функции выполняют различные действия, такие как подсчет всех строк в таблице, усреднение данных столбца и суммирование числовых данных. Агрегаты также могут искать в таблице, чтобы найти самые высокие значения “MAX” или самые низкие значения “MIN” в столбце. Как и в случае других типов запросов, вы можете ограничить или отфильтровать строки, с которыми работают эти функции, с помощью предложения WHERE. Например, если менеджеру необходимо знать, сколько сотрудников работает в организации, для получения этой информации можно использовать агрегатную функцию COUNT (*). Функция COUNT (*), показанная в приведенном ниже операторе SELECT, подсчитывает все строки в Таблица.

SELECT COUNT(*)
FROM employees;

  COUNT(*)
----------
        24

Таблица результатов для функции COUNT (*) представляет собой один столбец из одной строки, известный как скалярный результат или значение. Обратите внимание, что таблица результатов имеет заголовок столбца, который соответствует имени агрегатной функции, указанной в предложении SELECT.

Некоторые из часто используемых агрегатных функций приведены ниже:

SUM( [ALL | DISTINCT] expression )

AVG( [ALL | DISTINCT] expression )

COUNT( [ALL | DISTINCT] expression )

COUNT(*)

MAX(expression)

MIN(expression)

Ключевые слова ALL и DISTINCT являются необязательными и выполняются так же, как и с предложениями SELECT, которые вы научились писать. Ключевое слово ALL является значением по умолчанию, где эта опция разрешена. Выражение, указанное в синтаксисе, может быть константой, функцией, или любая комбинация имен столбцов, констант и функций, связанных арифметическими операторами. Однако агрегатные функции чаще всего используются с именем столбца. За исключением функции COUNT, все агрегатные функции не учитывают значения NULL.

Есть два правила, которые вы должны понимать и соблюдать при использовании агрегатов:

  • Агрегатные функции могут использоваться как в предложениях SELECT, так и в предложениях HAVING (предложение HAVING будет описано далее в этой главе).

  • Агрегатные функции нельзя использовать в предложении WHERE. Его нарушение приведет к тому, что групповая функция Oracle ORA-00934 не допускает здесь сообщения об ошибке.

Агрегатные функции могут использоваться как в предложениях SELECT, так и в предложениях HAVING (предложение HAVING будет описано далее в этой главе).

Агрегатные функции нельзя использовать в предложении WHERE. Его нарушение приведет к тому, что групповая функция Oracle ORA-00934 не допускает здесь сообщения об ошибке.

иллюстрации

Приведенный ниже запрос SELECT подсчитывает количество сотрудников в организации.

SELECT COUNT(*) Count
FROM employees;

COUNT
-----
   24

Приведенный ниже запрос SELECT возвращает среднюю зарплату сотрудников в организации.

SELECT AVG(Salary) average_sal
FROM employees;

AVERAGE_SAL
-----------
      15694

Приведенный ниже запрос SELECT возвращает сумму зарплат сотрудников в организации.

SELECT SUM(Salary) total_sal
FROM employees;

TOTAL_SAL
---------
    87472

Приведенный ниже запрос SELECT возвращает самые старые и самые последние даты приема сотрудников в организации.

SELECT MIN (hire_date) oldest, MAX (hire_date) latest
FROM employees;

OLDEST		LATEST
---------	-----------
16-JAN-83	01-JUL-2012

ГРУППА ПО

Агрегатные функции обычно используются вместе с предложением GROUP BY. Предложение GROUP BY позволяет использовать агрегатные функции для ответа на более сложные вопросы управления, такие как:

Какова средняя зарплата сотрудников в каждом отделе?

Сколько сотрудников работает в каждом отделе?

Сколько сотрудников работает над конкретным проектом?

Группировка за функцией устанавливает группы данных на основе столбцов и объединяет информацию только внутри группы. Критерий группировки определяется столбцами, указанными в предложении GROUP BY. Следуя этой иерархии, данные сначала организуются в группы, а затем предложение WHERE ограничивает строки в каждой группе.

Правила использования предложения GROUP BY

(1) Все зависимые столбцы или столбцы, используемые в функции GROUP BY, должны формировать основу группировки, следовательно, они также должны быть включены в предложение GROUP BY.

SELECT	DEPARTMENT_ID, SUM(SALARY)
FROM employees;

DEPARTMENT_ID,
*
ERROR at line 2:
ORA-00937: not a single-group group function

(2) Предложение GROUP BY поддерживает не псевдоним столбца, а фактические имена.

(3) Предложение GROUP BY может использоваться только с агрегатными функциями, такими как SUM, AVG, COUNT, MAX и MIN. Если оно используется с однорядными функциями, Oracle выдает исключение как «ORA-00979: не выражение GROUP BY» ,

(4) Агрегатные функции нельзя использовать в предложении GROUP BY. Oracle вернет сообщение об ошибке «ORA-00934: групповая функция не разрешена».

Ниже запроса перечислены количество сотрудников, работающих в каждом отделе.

SELECT  DEPARTMENT_ID,  COUNT (*)
FROM employees
GROUP BY DEPARTMENT_ID;

Аналогичным образом, ниже запрос, чтобы найти сумму зарплат для соответствующих идентификаторов работы в каждом отделе. Обратите внимание, что группа создана на основе отдела и идентификатора работы. Таким образом, они появляются в предложении GROUP BY.

SELECT DEPARTMENT_ID, JOB_ID, SUM (SAL)
FROM employees
GROUP BY DEPARTMENT_ID, JOB_ID;

Приведенный ниже запрос также дает тот же результат. Обратите внимание, что группировка основана на столбцах идентификатора отдела и идентификатора задания, но не используется для отображения.

SELECT SUM (SALARY)
FROM employees
GROUP BY DEPARTMENT_ID, JOB_ID;

Использование DISTINCT, ВСЕХ ключевых слов с агрегатными функциями

Задав ключевое слово DISTINCT во входном параметре, функция group by учитывает только уникальное значение столбца для агрегации. Указывая ключевое слово ALL с входным параметром, group by function учитывает все значения столбца для агрегации, включая нули и дубликаты. ALL является спецификацией по умолчанию.

Пункт HAVING

Предложение HAVING используется для агрегатных функций так же, как предложение WHERE используется для имен столбцов и выражений. По существу, предложения HAVING и WHERE выполняют то же самое, то есть фильтруют строки из включения в таблицу результатов на основе условия. , Хотя может показаться, что предложение HAVING отфильтровывает группы, это не так. Скорее, предложение HAVING фильтрует строки.

Когда все строки для группы удаляются, так же как и для группы. Подводя итог, можно отметить важные различия между предложениями WHERE и HAVING:

Предложение WHERE используется для фильтрации строк перед действием GROUPING (т. Е. Перед вычислением агрегатных функций).

Предложение HAVING фильтрует строки ПОСЛЕ действия GROUPING (т. Е. После вычисления агрегатных функций).

SELECT JOB_ID,	SUM (SALARY)
FROM employees
GROUP BY JOB_ID
HAVING SUM (SALARY) > 10000;

Предложение HAVING является условным параметром, который непосредственно связан с параметром предложения GROUP BY, поскольку предложение HAVING удаляет строки из таблицы результатов на основе результата предложения GROUP BY.

Понравилась статья? Поделить с друзьями:
  • Ошибка аирбаг ниссан кашкай j10
  • Ошибка агента обновлений windows 8024500c
  • Ошибка аирбаг ниссан альмера н16
  • Ошибка агента обновлений windows 8024402d
  • Ошибка аирбаг на ауди а4