I'm trying to generate a cars sales report using T-SQL.
The report must be grouped and ordered by Customer and Period (format M/yyyy)
The report result table must have the following columns:
You can find the SQL scripts I used to create and seed the database as well as the query I'm using here: https://dbfiddle.uk/wxFrkPuK
Here's the query I'm using in attempt to generate the report:
SELECT
c.Name_Customer AS 'Customer',
FORMAT(v.Sell_Date, 'M/yyyy') AS 'Period',
CASE
WHEN t.Name_Vehicle_Type = 'Car'
THEN (COUNT(v.ID_Vehicle))
ELSE NULL
END AS 'Cars quantity',
CASE
WHEN t.Name_Vehicle_Type = 'Car'
THEN SUM(v.Sell_Price)
ELSE NULL
END AS 'Cars total price',
CASE
WHEN t.Name_Vehicle_Type = 'Truck'
THEN (COUNT(v.ID_Vehicle))
ELSE NULL
END AS 'Trucks quantity',
CASE
WHEN t.Name_Vehicle_Type = 'Truck'
THEN SUM(v.Sell_Price)
ELSE NULL
END AS 'Trucks total price'
FROM
Customer AS c, Vehicle AS v, Vehicle_Type AS t
WHERE
c.ID_Customer = v.ID_Customer
AND v.ID_Vehicle_Type = t.ID_Vehicle_Type
GROUP BY
v.ID_Customer, FORMAT(v.Sell_Date, 'M/yyyy'),
c.Name_Customer, v.ID_Customer, t.Name_Vehicle_Type
HAVING
(t.Name_Vehicle_Type = 'Car' OR t.Name_Vehicle_Type = 'Truck')
ORDER BY
c.Name_Customer, 'Period'
Here's what I get when running the query:
Customer | Period | Cars qnt | Cars total price | Trucks qnt | Trucks total price |
---|---|---|---|---|---|
Jane Doe | 2/2023 | 2 | 53000.00 | NULL | NULL |
Jane Doe | 2/2023 | NULL | NULL | 2 | 380000.00 |
Jane Doe | 4/2023 | 2 | 27000.00 | NULL | NULL |
Jane Doe | 4/2023 | NULL | NULL | 2 | 137990.00 |
Jason St | 5/2023 | 2 | 72500.00 | NULL | NULL |
Jason St | 5/2023 | NULL | NULL | 2 | 330000.00 |
Jason St | 8/2023 | 1 | 25000.00 | NULL | NULL |
Jason St | 8/2023 | NULL | NULL | 1 | 57990.00 |
Mike Fen | 6/2023 | 3 | 93500.00 | NULL | NULL |
Mike Fen | 6/2023 | NULL | NULL | 2 | 330000.00 |
But I was expecting to receive:
Customer | Period | Cars qnt | Cars total price | Trucks qnt | Trucks total price |
---|---|---|---|---|---|
Jane Doe | 2/2023 | 2 | 53000.00 | 2 | 380000.00 |
Jane Doe | 4/2023 | 2 | 27000.00 | 2 | 137990.00 |
Jason St | 5/2023 | 2 | 72500.00 | 2 | 330000.00 |
Jason St | 8/2023 | 1 | 25000.00 | 1 | 57990.00 |
Mike Fen | 6/2023 | 3 | 93500.00 | 2 | 330000.00 |
Can you see the problem? It's generating an extra line with NULL values in certain cells. I wish to mix the two lines grouping by the customer and period as shown above.
You need to remove Name_Vehicle_Type
from the grouping, and instead use conditional aggregation.
Also:
[]
to quote column names, not ''
.ELSE NULL
is not actually necessary, it's the default.EOMONTH
to group by month, not FORMAT
as the strings don't sort properly and it's slow.IN
is shorter than OR
although it compiles to the same thing.HAVING
, otherwise use the WHERE
. The server can usually push it through to the lower level, but it's best to be explicit.SELECT
c.Name_Customer AS Customer,
EOMONTH(v.Sell_Date AS Period,
COUNT(CASE WHEN t.Name_Vehicle_Type = 'Car' THEN 1 END) AS [Cars quantity],
SUM (CASE WHEN t.Name_Vehicle_Type = 'Car' THEN v.Sell_Price END) AS [Cars total price],
COUNT(CASE WHEN t.Name_Vehicle_Type = 'Truck' THEN 1 END) AS [Trucks quantity],
SUM (CASE WHEN t.Name_Vehicle_Type = 'Truck' THEN v.Sell_Price END) AS [Trucks total price]
FROM Customer AS c
JOIN Vehicle AS v ON c.ID_Customer = v.ID_Customer
JOIN Vehicle_Type AS t ON v.ID_Vehicle_Type = t.ID_Vehicle_Type
WHERE t.Name_Vehicle_Type IN ('Car', 'Truck')
GROUP BY
c.ID_Customer,
c.Name_Customer,
EOMONTH(v.Sell_Date)
ORDER BY
c.Name_Customer,
EOMONTH(v.Sell_Date);