SQL Add Lead Time Day to MAX Ordered Date

Viewed 56

I have a Material table and I want to retrieve the latest Received Date, Expected Date and Order Date + Lead Time Days for a given order. So far I have the following that retrieves the MAX three dates, but I don't know how to add the lead time to the Ordered Date as well as retrieve the lead time for the MAX Ordered Date:

Select Top (1) Material.OrderID, LatestExpectedDate, LatestReceivedDate, LatestOrderedDate
from Material
left outer join (Select T1.OrderID, Max(T1.MaterialExpectedDate) as LatestExpectedDate from Material T1 where T1.FloorStock=0 and T1.MaterialAvailable=0
  Group by T1.OrderID) Tbl1 on Material.OrderID=Tbl1.OrderID
left outer join (Select T2.OrderID, Max(T2.MaterialReceivedDate) as LatestReceivedDate from Material T2 where T2.FloorStock=0 and T2.MaterialAvailable=0
  Group by T2.OrderID) Tbl2 on Material.OrderID=Tbl2.OrderID
left outer join (Select T3.OrderID, Max(T3.MaterialOrderedDate) as LatestOrderedDate from Material T3 where T3.FloorStock=0 and T3.MaterialAvailable=0
  Group by T3.OrderID) Tbl3 on Material.OrderID=Tbl3.OrderID

where Material.OrderID=*SomeGivenOrder*

I want to both retrieve the Lead Time for the latest MaterialOrderedDate as well as add the Lead Time in days to the MAX(MaterialOrderDate). Not being a SQL programmer I am stuck. If there is a better way to doing things, I am open to all suggestions.

Example data

OrderID FloorStock  LeadTime    MaterialAvailable   OrderedDate  ExpectedDate   ReceivedDate    
80         0        10                     0        7/01/22         8/23/22         8/23/22
80         0        5                      0        7/05/22         9/05/22
80         0        20                     0        7/10/22
106        1        0                      1            
148        0        15                     0        8/01/22

From the above if I asked for OrderID=80 I would expect to get

Order Date: 7/30/22 (7/10/22 + 20 day lead time)

Expected Date: 9/05/22

Received Date: 8/23/22

Thanks for the help!

3 Answers

Pretty sure you can greatly simplify all these subqueries into a single query. You really don't need a separate query for each column. Something like this should be what you are looking for.

For the lead time you want to add you can simply use DATEADD.

Select m.OrderID
    , LatestExpectedDate = Max(m.MaterialExpectedDate)
    , LatestReceivedDate = Max(m.MaterialReceivedDate)
    , LatestOrderedDate = Max(m.MaterialOrderedDate)
from Material m
where m.OrderID = *SomeGivenOrder*
group by m.OrderID
with data as (
    select *, first_value(LeadTime) over (order by OrderedDate desc) as last_LeadTime
    from Material
    where OrderID = ? and FloorStock = 0 and MaterialAvailable = 0
)
select
    dateadd(day, min(last_LeadTime), max(MaterialOrderedDate)) as OrderDate,
    max(MaterialExpectedDate) as ExpectedDate,
    max(MaterialReceivedDate) as ReceivedDate
from data;

https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=0af7cb9c156545f710fb169e2dbceb0c

This an approach can still be salvaged to accommodate the slight change in requirement to order on the date expression. If the data is large then it may still be beneficial to avoid the scalar subquery.

While I don't know the data there would appear to be some potential for two or more rows to tie for the ranking by order date plus lead time. In those instances I'm not sure what meaning to attach to the returned lead time value or whether to favor one over another.

with data as (
    select *,
        row_number() over (order by dateadd(day, LeadTime, OrderedDate) desc,
                                    LeadTime desc) as rn
    from Material
    where OrderID = ? and FloorStock = 0 and MaterialAvailable = 0
)
select
    min(case when rn = 1 then dateadd(day, LeadTime, OrderedDate) end) as OrderedDate,
    min(case when rn = 1 then LeadTime end) as SelectedLeadTime,
    max(ExpectedDate) as ExpectDate,
    max(ReceivedDate) as ReceivedDate
from data;

https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=df29081d9b0a769c55175c80aa692f72

What I thought was the correct answer to the problem did not work when I tested the SQL with a larger material table. The problem I was getting was that the incorrect Ordered Date and/or Lead Time were being reported for certain items. This problem had to do with the order of material items and what Ordered Date/Leadtime was being returned.

What I am now testing (based on Sean Lange's suggestion... and it appears so far to give the correct results) is as follows:

Select m.OrderID
    , LatestExpectedDate = Max(m.MaterialExpectedDate)
    , LatestReceivedDate = Max(m.MaterialReceivedDate)
    , LatestOrderedDate  = Max(DateAdd(Day, m.LeadTime, m.MaterialOrderedDate))
    , (SELECT Top (1) m1.LeadTime FROM OpMaterial m1 WHERE OrderID=Some_OrderID Order By DateAdd(Day, m1.LeadTime, m1.MaterialOrderedDate) desc ) As SelectedLeadTime
    , (SELECT Top (1) m2.MaterialOrderedDate FROM OpMaterial m2 WHERE OrderID=Some_OrderID Order By DateAdd(Day, m2.LeadTime, m2.MaterialOrderedDate) desc ) As SelectedOrderedDate
    from OpMaterial m
where m.OrderID = Some_OrderID and m.MaterialAvailable=0 and m.FloorStock=0
group by m.OrderID

The second sub query is there for testing purposes only so I can verify the ordered date and lead time are giving me the correct results. It will be removed in the final code.

Related