SQL-подзапрос в агрегатной функции
Я использую базу данных northwind, чтобы обновить свои навыки SQL, создав несколько более или менее сложных запросов. К сожалению, я не смог найти решение для моего последнего варианта использования: "Получите сумму пяти самых больших заказов для каждой категории в 1997 году."
задействованные таблицы:
Orders(OrderId, OrderDate)
Order Details(OrderId, ProductId, Quantity, UnitPrice)
Products(ProductId, CategoryId)
Categories(CategoryId, CategoryName)
я попробовал следующий запрос
SELECT c.CategoryName, SUM(
(SELECT TOP 5 od2.UnitPrice*od2.Quantity
FROM [Order Details] od2, Products p2
WHERE od2.ProductID = p2.ProductID
AND c.CategoryID = p2.CategoryID
ORDER BY 1 DESC))
FROM [Order Details] od, Products p, Categories c, Orders o
WHERE od.ProductID = p. ProductID
AND p.CategoryID = c.CategoryID
AND od.OrderID = o.OrderID
AND YEAR(o.OrderDate) = 1997
GROUP BY c.CategoryName
хорошо... Оказалось, что подзапросы в агрегатных функциях не допускаются. Я читал другие сообщения об этом проблема, но не может найти решение для моего конкретного случая использования. Надеюсь, вы сможете мне помочь...
4 ответов
подзапросы обычно не допускаются в агрегатных функциях. Вместо этого переместите агрегат внутри подзапрос. В этом случае вам понадобится дополнительный уровень подзапроса из-за top 5
:
SELECT c.CategoryName,
(select sum(val)
from (SELECT TOP 5 od2.UnitPrice*od2.Quantity as val
FROM [Order Details] od2, Products p2
WHERE od2.ProductID = p2.ProductID
AND c.CategoryID = p2.CategoryID
ORDER BY 1 DESC
) t
)
FROM [Order Details] od, Products p, Categories c, Orders o
WHERE od.ProductID = p. ProductID
AND p.CategoryID = c.CategoryID
AND od.OrderID = o.OrderID
AND YEAR(o.OrderDate) = 1997
GROUP BY c.CategoryName, c.CategoryId
использовать CTE С функции row_number функция ранжирования вместо чрезмерного подзапроса.
;WITH cte AS
(
SELECT c.CategoryName, od2.UnitPrice, od2.Quantity,
ROW_NUMBER() OVER(PARTITION BY c.CategoryName ORDER BY od2.UnitPrice * od2.Quantity DESC) AS rn
FROM [Order Details] od JOIN Products p ON od.ProductID = p.ProductID
JOIN Categories c ON p.CategoryID = c.CategoryID
JOIN Orders o ON od.OrderID = o.OrderID
WHERE o.OrderDate >= DATEADD(YEAR, DATEDIFF(YEAR, 0, '19970101'), 0)
AND o.OrderDate < DATEADD(YEAR, DATEDIFF(YEAR, 0, '19970101')+1, 0)
)
SELECT CategoryName, SUM(UnitPrice * Quantity) AS val
FROM cte
WHERE rn < 6
GROUP BY CategoryName
его определенно проблема под запросом здесь является отличная статья на этом (первоначально написано для доступа, но синтаксис идентичен), также orderdate = 1997 даст дату заказа для 1 января 1997 ' -- вам нужна datepart (год, orderdate) = 1997, как только у вас есть (до пяти) строк, возвращенных для каждой категории, вы можете инкапсулировать возвращенные строки и объединить их
Я столкнулся с очень похожей проблемой с подзапросом доступа, где записи были отсортированы по дате. Когда я использовал агрегатную функцию "Last", я обнаружил, что она прошла через все подзапросы и извлекла последнюю строку данных из таблицы Access, а не отсортированный запрос, как предполагалось. Хотя я мог бы переписать запрос, чтобы использовать агрегатную функцию в первом наборе скобок (как было предложено ранее) , мне было проще сохранить результаты запроса в виде таблицы в базе данных сортировка в порядке, который я хотел, а затем использовать" последнюю " агрегатную функцию для извлечения значений, которые я хотел. Я буду запускать запрос обновления в будущем, чтобы сохранить текущие результаты. Не эффективно, но эффективно.