First of all, there are some issues with your query:
Your SELECT
clause contains a column that is neither in GROUP BY
nor aggregated – WM_qtd
. You meant SUM(WM_qtd)
, didn't you?
In general, dates formatted with CONVERT(103)
cannot be meaningfully compared nor sorted. I would advise you either to use a different format (like 112
) or to use a different method of removing the time part at all and apply the formatting later on (just in the SELECT
clause or maybe not in SQL at all).
You are filtering the source dataset with the HAVING
clause, which is inefficient, because all the data would have to be pulled, grouped, and only then filtered. In this particular case it would be better to filter the data with the WHERE
clause.
Now as for your question... The result set you are after is basically the cross-product of all the relevant dates and all the relevant products (oops, sorry for the pun). It just includes some addition information, like Quantity.
So you need to obtain the two lists, dates and products, cross-join them, then you can outer-join the resulting set to Tb_InfoProduct
and group by date and product to obtain the numbers – same as you are already doing in your query, only the date and product columns your GROUP BY
and SELECT
clauses will be referencing must be those in the respective derived lists, not the ones in the Tb_InfoProduct
table.
For the purpose of my answer I'm assuming that the subset of Tb_InfoProduct
you are requesting contains all the dates and all the products that must be present in the output, so, to obtain the two lists, I'm merely selecting distinct dates and distinct products from the Tb_InfoProduct
subset. Here's an approximate solution in its entirety:
SELECT
Date = CONVERT(VARCHAR(10), d.Date, 103),
Product = CASE p.WM_Product
WHEN 1 THEN 'Product A'
WHEN 2 THEN 'Product B'
ELSE 'Product C'
END,
Quantity = SUM(WM_qtd)
FROM (
SELECT DISTINCT Date = DATEADD(DAY, DATEDIFF(DAY, 0, WM_data), 0)
FROM Tb_InfoProduct
WHERE WM_data >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 4, 0)
) d
CROSS JOIN (
SELECT DISTINCT WM_Product
FROM Tb_InfoProduct
WHERE WM_data >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 4, 0)
) p
LEFT JOIN (
SELECT
Date = DATEADD(DAY, DATEDIFF(DAY, 0, WM_data), 0),
WM_Product
FROM Tb_InfoProduct
WHERE WM_data >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()) - 4, 0)
) i ON d.Date = i.Date AND p.WM_Product = i.WM_Product
GROUP BY
d.Date,
p.WM_Product
ORDER BY
d.Date,
p.WM_Product
If the requested subset may omit some dates and/or products which you would prefer to include in the output, you should build the list(s) differently. For instance, you could use a Products
referencing table for the list of products, if you have one, of course. As for the dates, you might need to generate the list of dates for the given range, as suggested by @OMG Ponies (and this question might help you with that: Get a list of dates between two dates using a function).