Select second latest date for each group in the table - sql

hi guys for a report I need to find the second latest date for every specific SKU
down below is the code I am working with.
this is a simplified example.
SKU | plannendstartinflow
11538 2015-03-12
11538 2016-03-12
11538 2017-03-12
33252 2018-02-17
what i need to become is this because it is the second latest date of that SKU
SKU | plannendstartinflow
11538 2016-03-12
code below is the code that is used right now for the latest date
update :
select * from
(select
case when DATEDIFF(MONTH,MAX(PlannedEndInflow),GETDATE()) > 3 then max(PlannedEndInflow) else null end as datum
--case when DATEDIFF(MINUTE,od.PlannedEndInflow,Max(od.PlannedEndInflow)) > 1 then max(od.PlannedEndInflow) else null end as test
,od.odscheduleid
,lc.shortname as line
,ar.erpcode as SKU
,ar.shortname as Article
,od.PlannedEndInflow
,od.[PlannedEndInflow] as second_max_date
,Max(od.PlannedEndInflow) as max_date
,st.shortname as 'status'
,od.[ShortName] as 'order'
,od.[ERPCode]
,od.[ASCode]
,od.[PlannedQuantity] as 'PlannedQuantity [PC]'
,cast(od.[PlannedQuantity]*ar.Volume/100 as decimal(12,2)) as 'PlannedQuantity [HL]'
,od.[PlannedChangeoverTime]
,od.[PlannedSpeed]
,od.[PlannedSpeedRatio],
ROW_NUMBER()over(partition by ar.erpcode order by od.PlannedEndInflow desc) as rn
from(
[RM].[TblDatODSchedule] od
inner join [EM].[TblLstLocation] lc on od.locationid=lc.locationid
inner join [RM].[TblLstART] ar on od.artid=ar.artid
inner join [EM].[TblLstStatus] st on od.statusid=st.statusid
)
--where lc.shortname = 'lb1' and PlannedEndOutflow > '20190101'
group by
ar.ERPCode , lc.ShortName,od.odscheduleid,ar.shortname
,od.[PlannedStartInflow]
,od.[PlannedEndInflow]
,st.shortname
,od.[ShortName]
,od.[ERPCode]
,od.[ASCode]
,od.[PlannedQuantity]
,ar.Volume
,od.[PlannedChangeoverTime]
,od.[PlannedSpeed]
,od.[PlannedSpeedRatio]
) t2 where rn=2;
thanks in advance

You can use the following code to get the second latest date:
select * from
(select SKU,plannendstartinflow,
ROW_NUMBER()over(partition by SKU order by plannendstartinflow desc) as rn
from test
)t where rn=2;
EDIT:
select * from
(select SKU,plannendstartinflow, --similarly add other columns
ROW_NUMBER()over(partition by SKU order by plannendstartinflow desc) as rn
from (
--Put Your Subquery here
)t1
)t2 where rn=2;
EDIT2: To select max and second max date.
select SKU,min(plannendstartinflow) as secondmaxdate,max(plannendstartinflow) as
maxdate from
(select * from (select SKU,plannendstartinflow,
ROW_NUMBER()over(partition by SKU order by plannendstartinflow desc) as rn
from test
)t where rn<3
)t1 group by SKU;

Related

Filter the table with latest date having duplicate OrderId

I have following table:
I need to filter out the rows for which start date is latest corresponding to its order id .With reference to given table row no 2 and 3 should be the output.
As row 1 and row 2 has same order id and order date but start date is later than first row. And same goes with row number 3 and 4 hence I need to take out row no 3 . I am trying to write the query in SQL server. Any help is appreciated.Please let me know if you need more details.Apologies for poor English
You can do this easily with a ROW_NUMBER() windowed function:
;With Cte As
(
Select *,
Row_Number() Over (Partition By OrderId Order By StartDate Desc) RN
From YourTable
)
Select *
From Cte
Where RN = 1
But I question the StartDate datatype. It looks like these are being stored as VARCHAR. If that is the case, you need to CONVERT the value to a DATETIME:
;With Cte As
(
Select *,
Row_Number() Over (Partition By OrderId
Order By Convert(DateTime, StartDate) Desc) RN
From YourTable
)
Select *
From Cte
Where RN = 1
Another way using a derived table.
select
t.*
from
YourTable t
inner join
(select OrderId, max(StartDate) dt
from YourTable
group by OrderId) t2 on t2.dt = t.StartDate and t2.OrderId = t.OrderId

Select the max and second max value from a select, and group them?

I've been battling with this problem for a week now and I need help.
I have a select statement that generates a table showing every product, and an import date per product.
How can I make a new table that shows:
Product in one column.
Last date in another column.
Date before the last in the last column.
And group them by product.
I've scoured the net for information, and I can't get it to work. Most of the examples show how to find just one second last value from a table. I'd like to show it per product.
Also, I can't use LIMIT due to using MSSQL.
Table from query
Query
SELECT
S.acIdent AS Product,
CAST((SELECT top 1 adDate FROM the_move WHERE ackey = MI.acKey) AS date) AS ImportDate
FROM tHE_Stock S
LEFT JOIN tHE_MoveItem MI
ON S.acIdent = MI.acIdent
WHERE
( S.acWarehouse = '00051' ) AND
(
( RIGHT(LEFT(MI.acKey,5),3) = '100' ) OR
( RIGHT(LEFT(MI.acKey,5),3) = '190' )
)
ORDER BY
S.acIdent,
CAST((SELECT top 1 adDate FROM the_move WHERE ackey = MI.acKey) AS date)
DESC
You can query using row_number and pivot as below:
Select Product, [1] as [LastDate], [2] as [Last Before Last Date] from (
Select top (2) with ties *, RowN=Row_Number() over(partition by Product order by ImportDate desc) from Products
Order by (Row_Number() over(partition by Product order by ImportDate desc) -1)/2+1
) a
pivot (max(ImportDate) for RowN in([1],[2])) p
Output using this query for your similar input as below:
+---------+------------+-----------------------+
| Product | LastDate | Last Before Last Date |
+---------+------------+-----------------------+
| 075031 | 2014-07-08 | 2014-06-19 |
| 075032 | 2014-12-09 | NULL |
| 075034 | 2016-03-10 | 2014-07-08 |
| 075036 | 2016-03-08 | 2015-09-08 |
+---------+------------+-----------------------+
So, if I understand you correctly, you need the acIdent, then the latest import date, then the second to latest import date.
The difficult thing is the second to latest import date. For this, you need to exclude the latest import date.
This might work:
SELECT S.acIdent AS Product,
(SELECT MAX(adDate)
FROM tHE_MoveItem MI2
WHERE MI2.s.acIdent = MI.acIdent) AS LastImportDate,
(SELECT MAX(adDate)
FROM tHE_MoveItem MI2
WHERE MI2.acIdent = MI.acIdent
AND MI2.ImportDate != (SELECT MAX(ImportDate)
FROM tHE_MoveItem MI3
WHERE MI2.s.acIdent = MI3.acIdent))
AS PreviousImportDate,
FROM tHE_Stock S
INNER JOIN tHE_MoveItem MI
ON s.acIdnet = MI.acIdent
You can use rownumber instead of max, to find both the last and secondlast date.
Declare #mytable table (productnr varchar(10), importdate date)
insert into #mytable values
('075031', '2014-07-08'),
('075031', '2014-07-07'),
('075031', '2014-07-06'),
('075032', '2014-07-10'),
('075032', '2014-07-09'),
('075032', '2014-07-06')
;with products_cte as
(select productnr,importdate, ROW_NUMBER() over (partition by productnr order by importdate desc) rn
from #mytable
)
select t1.productnr, t1.importdate lastDate,t2.importdate SecondLastDate
from products_cte t1
left join products_cte t2 on t1.productnr = t2.productnr and t2.rn = 2
where t1.rn = 1
One more option with lead and lag.
select productnr,importdate as lastdate,prev as secondlastdate
from (select productnr,importdate
,lead(importdate) over(partition by productnr order by importdate) as nxt
,lag(importdate) over(partition by productnr order by importdate) as prev
from tbl
) t
where nxt is null
lead on the date for last row (ordered by importdate per productnr) would be null and lag gives you the previous date before the lastdate.

SQL Find latest record meeting certain criteria

I feel like this should be easy but I'm having a hard time getting it. We have a table with UnitID, DateTimeStamp, and UnitStatus. Like so:
I'm trying to find the latest record (based on DateTimeStamp) for each unit if their last UnitStatus was LO. So in the screenshot I've taken of a sample database I would be looking to have it return:
E02 2017-02-06 03:00:00 LO .....
E04 2017-02-06 06:00:00 LO
(It would not return E03 because E03 had a UnitStatus of AV after their UnitStatus of LO)
I've tried doing max(cdts) with different where statements. Joining a query to another query that used max(cdts). But whatever I try I never get the results I'm looking for.
Try this with desc keyword
SELECT * from table
WHERE UnitStatus = 'LO'
ORDER BY DateTimeStamp desc
Try using window function row_number to get the latest record for each UnitID
Select *
From (
Select
t.*,
Row_number() over (partition by UnitID order by datetimestamp desc) rn
From your_table t
Where UnitStatus = 'LO'
) t where rn = 1
with cte as (
select *,
Row_number() over (partition by UnitID order by DateTimeStamp desc) as rn
from theTable
)
select *
from cte
where rn = 1
and UnitStatus = 'LO'
SELECT DISTINCT retrieves the UnitIDs, the OUTER APPLYed subselect retrieves the unitIDs with most recent status 'LO':
with t as (select distinct unitid from SO42060982)
select t.*, sub.*
from t
outer apply
(select top 1 * from SO42060982 sub
where t.UnitID = sub.UnitID order by DateTimeStamp desc) sub
where sub.UnitStatus = 'LO'
Try this. Update After reading updated question, I've updated my answer
SELECT tbl1.*
FROM defaulttable as tbl1
RIGHT JOIN
(
SELECT UnitStatus FROM defaulttable
WHERE UnitStatus = 'LO'
) as tbl2
ON tbl1.UnitStatus != tbl2.UnitStatus
WHERE tbl1 != 'LO'
ORDER BY tbl1.DateTimeStamp
Use the ROW_NUMBER() function to get the latest record for each UnitId as specified above. As the second step filter the records based on their rowindex and Status, Then i think you should be able to achieve what you were looking for
Step 1
SELECT U.*,
ROW_NUMBER() OVER (PARTITION BY UNITID ORDER BY DATETIMESTAMP DESC) SNO
INTO #UNITSTEMP
FROM UNITS U
Step 2
SELECT DISTINCT * FROM #UNITSTEMP WHERE SNO = 1 AND UNITSTATUS = 'LO'
After running the above queries your result will be as shown in the screenshot below

How to query specific values for some columns and sum of values in others SQL

I'm trying to query some data from SQL such that it sums some columns, gets the max of another column and the corresponding row for a third column. For example,
|dataset|
|shares| |date| |price|
100 05/13/16 20.4
200 05/15/16 21.2
300 06/12/16 19.3
400 02/22/16 20.0
I want my output to be:
|shares| |date| |price|
1000 06/12/16 19.3
The shares have been summed up, the date is max(date), and the price is the price at max(date).
So far, I have:
select sum(shares), max(date), max(price)
but that gives me an incorrect price.
EDIT:
I realize I was unclear in my OP, all the other relevant data is in one table, and the price is in other. My full code is:
select id, stock, side, exchange, max(startdate), max(enddate),
sum(shares), sum(execution_price*shares)/sum(shares), max(limitprice), max(price)
from table1 t1
INNER JOIN table2 t2 on t2.id = t1.id
where location = 'CHICAGO' and startdate > '1/1/2016' and order_type = 'limit'
group by id, stock, side, exchange
You can do this with window functions and aggregation. Here is an example:
select sum(shared), max(date), max(case when seqnum = 1 then price end) as price
from (select t.*, row_number() over (order by date desc) as seqnum
from t
) t;
EDIT:
If the results that you are looking at are in fact the result of a query, you can do:
with t as (<your query here>)
select sum(shared), max(date), max(case when seqnum = 1 then price end) as price
from (select t.*, row_number() over (order by date desc) as seqnum
from t
) t;
Heres one way to do it .... the join would obviously include the ticker symbol for the share also
select
a.sum_share,
a.max_date
b.price
FROM
(
select ticker , sum(shares) sum_share, max(date) max_date from table where ticker = 'MSFT' group by ticker
) a
inner join table on a.max_date = b.date and a.ticker = b.ticker

selecting all values in GroupBy

I have a scenario wherein i have three columns in my table. ID(String),Desc (string) TerminationDate, Last Update Date(Time).
There is no primary key, so there might be multiple rows with same set of data but LastUpdate Date will always be different.
I need to write a SP wherein i need to get the latest modified result(ID,Desc, termination date). pls see the example below
ID Desc TerminationDate LastUpdtDt
A test 01-01-2013 01-01-2013
A test1 01-03-2013 25-01-2013
A test 01-01-2013 26-03-2013
B test 01-01-2011 01-01-2013
The result i shuld get is
A test 01-01-2013 26-03-2013
B test 01-01-2011 01-01-2013
Let me know in case you need more information.
SELECT ID, [DESC], TerminationDate, LastUpdtDt
FROM
(
SELECT ID, [DESC], TerminationDate, LastUpdtDt,
ROW_NUMBER() OVER(PARTITION BY ID
ORDER BY LastUpdtDt DESC) rn
FROM TableName
) ss
WHERE rn = 1
SQLFiddle Demo
You could return the rows with the max(LastUpdtDt) using a subquery:
select t1.id,
t1.[desc],
t1.terminationdate,
t1.LastUpdtDt
from yt t1
inner join
(
select max(LastUpdtDt) LastUpdtDt, id
from yt
group by id
) t2
on t1.id = t2.id
and t1.LastUpdtDt = t2.LastUpdtDt;
See SQL Fiddle with Demo.
SELECT ID ,
DESC ,
TERMINATION_DATE ,
LAST_UPDATE
FROM ( SELECT ID ,
DESC ,
TERMINATION_DATE ,
LAST_UPDATE ,
ROW_NUMBER() OVER ( PARTITION BY ID ORDER BY LAST_UPDATE DESC ) SERIAL_ORDER
FROM LAST_UPDATE
) B
WHERE SERIAL_ORDER = 1