Я хочу сгруппировать по дате и платежу, а также названию и коду филиала. Я не знаю, почему этот SQL-запрос возвращает эту ошибку:
Столбец «FactSalesTable.SalesTotal» недопустим в списке выбора, поскольку он не содержится ни в агрегатной функции, ни в предложении GROUP BY.
SELECT
FactSalesTable.Date,
FactSalesTable.PaymentID,
Branch.* ,
SUM(FactSalesTable.SalesTotal) AS TotalSales,
AVG (FactSalesTable.SalesTotal) OVER (PARTITION BY Branch.BCode) AS AvgSales,
CASE
WHEN SUM(FactSalesTable.SalesTotal) OVER (PARTITION BY Branch.BCode) /AVG(FactSalesTable.SalesTotal) OVER (PARTITION BY Branch.BCode) > 1 THEN 'Above Avg'
WHEN SUM(FactSalesTable.SalesTotal) OVER (PARTITION BY Branch.BCode)/AVG(FactSalesTable.SalesTotal) OVER (PARTITION BY Branch.BCode) = 1 THEN 'Avg'
ELSE 'Below Avg'
END AS SalesResult
FROM Branch
LEFT JOIN FactSalesTable ON Branch.BCode = FactSalesTable.BCode
WHERE FactSalesTable.SalesTotal > 0 AND Branch.BCode = 1021
GROUP BY FactSalesTable.Date, Branch.BranchName, Branch.BCode, FactSalesTable.PaymentID
ORDER BY FactSalesTable.Date DESC
Я хочу показать общий объем продаж по дате, например
Это фрагмент запроса без группы по
🤔 А знаете ли вы, что...
SQL был создан в 1970-х годах компанией IBM.
Вы агрегируете данные на двух уровнях:
SUM(SalesTotal)
для каждого отделения и платежа, как определено в GROUP BY
.SUM(...) OVER(...)
и AVG(...) OVER(...)
для всех платежей по филиалу, как определено спецификатором окна OVER(,,,)
.Ваша проблема в том, что ваши оконные функции агрегации пытаются получить доступ к необработанным данным, хотя я считаю, что вы собираетесь суммировать и усреднять сгруппированные значения. Вместо AVG(SalesTotal) OVER(...)
, я думаю, вам нужен AVG(SUM(SalesTotal)) OVER(...)
. Однако для случаев SUM()
в расчете SalesResult
я считаю, что вам нужна только простая (не оконная) ветвь и сумма платежа SUM(SalesTotal)
, а не сумма сумм на уровне ветки.
Кроме того, если вы ограничили FactSalesTable.SalesTotal > 0
, строки FactSalesTable
должны присутствовать, а ваш LEFT JOIN
фактически является INNER JOIN
.
Следующее должно быть ближе к тому, чего вы пытаетесь достичь.
SELECT
FactSalesTable.Date,
FactSalesTable.PaymentID,
Branch.* ,
SUM(FactSalesTable.SalesTotal) AS TotalSales,
AVG (SUM(FactSalesTable.SalesTotal)) OVER(PARTITION BY Branch.BCode) as AvgSales ,
case
when SUM(FactSalesTable.SalesTotal)
/ AVG(SUM(FactSalesTable.SalesTotal)) OVER(PARTITION BY Branch.BCode) > 1
THEN 'Above Avg'
when SUM(FactSalesTable.SalesTotal)
/ AVG(SUM(FactSalesTable.SalesTotal)) OVER(PARTITION BY Branch.BCode) = 1
THEN 'Avg'
else 'Below Avg'
end as SalesResult
FROM Branch
LEFT JOIN FactSalesTable ON Branch.BCode = FactSalesTable.BCode
WHERE FactSalesTable.SalesTotal > 0 and Branch.BCode = 1021
Group BY FactSalesTable.Date,Branch.BranchName ,Branch.BCode,FactSalesTable.PaymentID
ORDER BY FactSalesTable.Date DESC
Результаты:
См. эту db<>fiddle. (Спасибо Барту МакЭндри за настройку тестовых данных.)
Вероятно, существуют способы дальнейшей реструктуризации запроса, чтобы ограничить избыточные выражения и улучшить читаемость, например, переместить исходную логику группировки в подзапрос или CTE и выполнить оконные операции в конечном/внешнем запросе. Другой вариант — обернуть всю логику платежей в CROSS APPLY
.