简体   繁体   中英

SQL double group by

I need to select employees' names from those who has sold products, for the biggest total sum of money in each of the years, in Northwind database. I've managed to create a valid query like this:

WITH TEMP_QUERY AS
    (
        SELECT DATEPART(YEAR, OrderDate) AS 'Year', FirstName + ' ' + LastName AS 'Employee', SUM(UnitPrice * Quantity) AS 'Total year sale' FROM Employees
        INNER JOIN Orders ON Employees.EmployeeID = Orders.EmployeeID
        INNER JOIN [Order Details] ON Orders.OrderID = [Order Details].OrderID
        GROUP BY FirstName + ' ' + LastName, DATEPART(YEAR, OrderDate)
    )

    SELECT DATEPART(YEAR, OrderDate) AS 'Year', FirstName + ' ' + LastName AS 'Employee', SUM(UnitPrice * Quantity) AS 'Total year sale' FROM Employees
    INNER JOIN Orders ON Employees.EmployeeID = Orders.EmployeeID
    INNER JOIN [Order Details] ON Orders.OrderID = [Order Details].OrderID
    GROUP BY FirstName + ' ' + LastName, DATEPART(YEAR, OrderDate)
    HAVING SUM(UnitPrice * Quantity) IN
    (
        SELECT MAX(main.[Total year sale]) FROM TEMP_QUERY AS main 
        INNER JOIN TEMP_QUERY AS e ON e.Employee = main.Employee
        GROUP BY main.Year
    )
    ORDER BY 1;

However I wonder if there's a simpler way of doing this with or without CTE (probably is) Database scheme. https://docs.yugabyte.com/images/sample-data/northwind/northwind-er-diagram.png

First, your main query is the same as those one used in CTE (except HAVING and ORDER BY clauses), so you can just write it as SELECT... FROM temp_query .

Second, I suggest you not to use the combination of FirstName and LastName for aggregation in CTE, since in theory there can be multiple rows for different employees with same values. You have the EmployeeId you a free to use it instead.

Third, since now the main query does not have any aggregation, you do not need a HAVING clause, it can be replaced by WHERE clause.

Fourth, the filter condition (in HAVING clause of your query) does not need self joining of CTE for getting the maximum of Total year sale . Just select MAX("Total year sale") with GROUP BY year .

Fifth, since I have suggested to use EmployeeId to perform the aggregation in CTE, join the Employees table to get the corresponding FirstName and LastName values for an employee in results.

Finally the query would look like this

WITH employee_total_sales (
    SELECT 
        e.employeeid,
        DATEPART(YEAR, OrderDate) AS year, 
        SUM(UnitPrice * Quantity) AS total_sale 
    FROM Employees e
    INNER JOIN Orders o ON e.EmployeeID = o.EmployeeID
    INNER JOIN [Order Details] od ON o.OrderID = od.OrderID
    GROUP BY e.employeeid, DATEPART(YEAR, OrderDate)
)
SELECT 
    year AS "Year",
    FirstName + ' ' + LastName AS "Employee",
    total_sale AS "Total year sale"
FROM employee_total_sales ets
JOIN employees e ON e.employeeid = ets.employeeid
WHERE total_sales IN (
    SELECT 
        MAX(total_sale)
    FROM employee_total_sales
    GROUP BY year
)
ORDER BY year

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM