Reputation: 1059
I've two tables : Materials and inventory.
I want to get the list of all the materials with their latest stock if available, otherwise just zero.
TABLE - MATERIALS
id | material |
==========================
1 |Lily - Blue
2 |Lily - Orange
3 |Lily - White
4 |Rose - Blue
5 |Rose - Orange
6 |Rose - White
TABLE - INVENTORY
id | date | material | final_stock | entry_time |
=========================================================================
1 |2018-05-18 |Lily - Blue | 30 | 2018-05-18 09:06:48 |
2 |2018-05-18 |Lily - white| 10 | 2018-05-18 10:32:27 |
3 |2018-05-18 |Lily - Blue | 90 | 2018-05-18 15:30:31 |
my query :
select materials.material, max(inventory.final_stock) from materials left join
inventory on materials.material = inventory.material
output
material | max(inventory.final_stock)|
========================================
Lily - Blue |90
output required >>
date | material | max(inventory.final_stock)|
======================================================
2018-05-18 | Lily - Blue |90
2018-05-18 | Lily - Orange|0
2018-05-18 | Lily - white |10
2018-05-18 | Rose - Blue |0
2018-05-18 | Rose - Orange|0
2018-05-18 | Rose - white |0
Upvotes: 1
Views: 75
Reputation: 575
just add a sub-query to populate the missing elements, then use conditionals to fill in the Null fields. The below query matches the conditions asked for in your question.
Be aware in a 'live' system I would not just seek the max(final_stock) on any given date as the 'final_stock' item. If the 'entry_time' is supposed to the the most recent entry for a given stock item I would re-work this query to use that as the latest 'inventory entry' to be referenced. But to do so opens the issue of whether someone is allowed in your system to back-date inventory entries.
SELECT
ifnull(C.date,(SELECT max(date) FROM inventory)) AS date,
C.material,
ifnull(max(D.final_stock),0) AS final_stock
FROM (
SELECT
max(B.date) AS date,
A.material
FROM materials A LEFT JOIN inventory B ON A.material = B.material
GROUP BY A.material
) AS C LEFT JOIN inventory D ON C.material=D.material AND C.date = D.date
GROUP BY C.material,C.date
ORDER BY C.material,C.date
results below
date material final_stock
2018-05-18 Lily - Blue 90
2018-05-18 Lily - Orange 0
2018-05-18 Lily - White 10
2018-05-18 Rose - Blue 0
2018-05-18 Rose - Orange 0
2018-05-18 Rose - White 0
If you are allowed to make use of the entry_time field then the query below is a better solution. This query also no longer has to use aggregation in the outer query. The result for your dataset is the same.
SELECT
ifnull(D.date,(SELECT max(date) FROM inventory)) AS date,
C.material,
ifnull(D.final_stock,0) AS final_stock
FROM (
SELECT
max(B.entry_time) as entry_time,
A.material
FROM materials A LEFT JOIN inventory B ON A.material = B.material
GROUP BY A.material
) AS C LEFT JOIN inventory D ON
C.material=D.material AND
C.entry_time = D.entry_time
ORDER BY C.material
Upvotes: 0
Reputation: 50173
You can also do the JOIN
with subquery
:
select m.material, coalesce(i.final_stock, 0) as final_stock
from materials m
left outer join (select material, max(final_stock) final_stock
from INVENTORY
group by material
) i on i.material = m.material;
Upvotes: 0
Reputation: 175
Try this;
with inv as
(
select m.material
,i.date
,i.final_stock
,Max(i.Entry_time) over (Partition By i.material) maxLog
from materials m
left join inventory i on m.material = i.material
)
Select date, material, final_stock
From inv where entry_time = maxLog
Upvotes: 0
Reputation: 1270513
One method is a correlated subquery:
select m.*,
coalesce( (select i.final_stock
from inventory i
where i.material = m.material
order by i.entry_time desc
limit 1
), 0) as final_stock
from materials m;
Note that one of the major reasons for having an id
in a table is so it can be used for foreign key relationships. Hence, inventory
should have a material_id
column, not a material
column.
Upvotes: 1