#sql #postgresql #group-by #window-functions
Вопрос:
Я знаю, что здесь нет смысла использовать Group by. Но я кое-что экспериментировал и получил ошибку, в которой говорилось, что стоимость столбца должна быть в группе или использоваться в агрегатной функции. Я хочу понять, что происходит внутри и почему логика неверна. Допустим, у меня есть столик :
name | date | category | cost, jill | 2019-04-01 | pen | 10 , jill | 2019-04-01 | pen | 40 , jill | 2019-04-01 | coat | 20 , Farida | 2019-03-01 | coat | 25, Farida | 2019-03-02 | coat | 15
Написание кода в виде :
select first_name, cast(o_date as date), sum(cost) over(partition by first_name) as tot from tab1 group by 1,2;
Согласно запросу, будет выполнена первая группа by, которая даст:
Jill | 2019-04-01 Farida | 2019-03-01 Farida | 2019-03-02
а затем мы сжимаем строки, беря сумму столбца затрат, но для каждого раздела first_name.
Я ожидаю, что результат будет таким
Jill | 2019-04-1 | 50 Farida | 2019-03-01 | 60 Farida | 2019-03-02 |60
Код отлично работает без предложения group by(которое я уже знаю, как это сделать). Почему мы не можем использовать группу здесь? Пожалуйста, скажите, что привело к неправильному коду?
Комментарии:
1. Сообщение об ошибке очень четкое, чего именно вы не понимаете? Здесь вам не нужно суммировать по окну, вам нужна сумма для каждой группы.
2. Привет, Стю, мне нужна сумма затрат для каждого раздела(имя пользователя), а не для группы
3. Определение функции окна
over(partition by first_name)
послеgroup by 1
, например, группировка по имени пользователя бесполезна. Было бы более разумно разделять поcategory
, аfirst_name
не в функции окна.
Ответ №1:
Предложение, за sum()
которым следует OVER
предложение, не является функцией агрегации, хотя оно имеет то же имя, что и одно.
Из этого следует , что cost
в вашем запросе не является ни аргументом функции агрегации, ни GROUP BY
предложением.
Но вы можете использовать функцию окна (кстати, не «окна») для результата функции агрегирования.
Таким образом, допускается следующее. sum()
сначала используется в качестве функции агрегирования cost
, а затем для этого используется функция окна sum()
.
SELECT first_name, cast(o_date AS date), sum(sum(cost)) OVER (PARTITION BY first_name) AS tot FROM tab1 GROUP BY first_name, cast(o_date AS date);
И в качестве примечания: я рекомендую не использовать порядковые номера столбцов в GROUP BY
предложениях. Это слишком легко испортить. Вместо этого предпочитайте использовать выражения столбцов.
Комментарии:
1. Большое спасибо @sticky bit