SQL query to sort data by time and date and then select only the newest record - sql

I am trying to trying to update create a query that will sort data by Date and time, find the newest record and then update another field in the record marking it as so.
Take my life harder the time and data are two separate fields and the time is also a string.
So here is what I have so far,
UPDATE server.ESCC_HWAY_ASSETS_GULLIES_N
set CURRENT_REC = 'Y'
From server.ESCC_HWAY_ASSETS_GULLIES_N A
inner join (
SELECT GULLY_ID, Max([DATE]) AS MaxDate, MAX([TIME]) AS MaxTime
FROM server.ESCC_HWAY_ASSETS_GULLIES_N B
GROUP BY GULLY_ID, [DATE] ) B
on A.GULLY_ID = B.GULLY_ID and A.[DATE] = B.MaxDate and A.[TIME] = B.MaxTime
This results in data that is sorted by time and date but it updates all fields it finds, apart from on dates where there are two entries. Then it only updates the newest record.
I am testing on a single record - B47605 which gives the following results on this queuer
SELECT GULLY_ID, Max([DATE]) AS MaxDate, MAX([TIME]) AS MaxTime
FROM ESMAPADMIN.ESCC_HWAY_ASSETS_GULLIES_N B
WHERE GULLY_ID = 'B47605'
GROUP BY GULLY_ID, [DATE]
Gully_ID MaxDate MaxTime
B47605 2008-03-12 00:00:00.000 09:02:29
B47605 2008-09-19 00:00:00.000 09:51:14
B47605 2009-02-16 00:00:00.000 11:18:28
B47605 2009-08-21 00:00:00.000 12:34:45
B47605 2010-03-16 00:00:00.000 09:22:26
B47605 2010-08-25 00:00:00.000 11:19:55
B47605 2011-03-07 00:00:00.000 12:19:56
B47605 2012-05-02 00:00:00.000 20:57:54
The result I would like is to only have the newest record returned so -
Gully_ID MaxDate MaxTime
B47605 2012-05-02 00:00:00.000 20:57:54
I am not sure how to go from where i am to where i need to be, so any help would be appreciated.

Assuming you are using SQL Server 2005+ (because of the [] I see)
;WITH latestResult
AS
(
SELECT Gully_ID, MaxDate, MaxTime,
ROW_NUMBER() OVER (PARTITION BY Gully_ID
ORDER BY MaxDate DESC, MaxTime DESC) RN
FROM tableName
)
SELECT Gully_ID, MaxDate, MaxTime
FROM latestResult
WHERE RN = 1
SQLFiddle Demo

Ended up using the following, thanks to all that helped me with this.
UPDATE ....
set CURRENT_REC = 'Y'
where [objectID] in
(
select [objectID] from
(
SELECT [objectID],[GULLY_ID], [date], [time],
ROW_NUMBER() over (partition by gully_id order by date desc, time desc) rown
FROM ....
) as t
where rown=1
)

Related

SQL: Difference Between Current Row of StartTime Column And Previous Row of EndTime Column

I have a Table in which there are multiple columns but I need to find the Difference Between Current Row of StartTime Column And Previous Row of EndTime Column.
Example is the Following output.
Batch Number Start Time End Time Difference
100004 8:00:00 8:03:30
100005 8:05:00 8:07:00 00:01:30
100006 8:08:40 8:15:00 00:01:40
32141 8:18:00 8:22:45 00:03:00
84230 8:25:10 8:33:42 00:02:25
23444 8:40:00 8:43:00 00:06:18
100001 8:50:00 8:52:00 00:07:00
I am new to SQL and am using SQL SERVER 2008 R2.
Please help me to get the output in Simple Select Query.
CREATE TABLE #Batches
(
BatchID INT,
StartTime Datetime,
EndTime Datetime,
)
INSERT INTO #Batches
VALUES
(100004,'2016-05-16 08:00:00','2016-05-16 08:03:30'),
(100005,'2016-05-16 08:05:00','2016-05-16 08:07:00'),
(100006,'2016-05-16 08:08:40','2016-05-16 08:15:00'),
(32141 ,'2016-05-16 08:18:00','2016-05-16 08:22:45'),
(84230 ,'2016-05-16 08:25:10','2016-05-16 08:33:42'),
(23444 ,'2016-05-16 08:40:00','2016-05-16 08:43:00'),
(100001,'2016-05-16 08:50:00','2016-05-16 08:52:00')
;WITH CTE AS
(
SELECT
BatchID,
StartTime,
EndTime,
ROW_NUMBER() OVER (ORDER BY StartTime) AS Seq
FROM #Batches
)
SELECT
b.BatchID,
b.StartTime,
b.EndTime,
CONVERT(VARCHAR(20), DATEADD(SECOND,DATEDIFF(SECOND, bl.EndTime,b.StartTime),0),108) AS Diff,
DATEADD(SECOND,DATEDIFF(SECOND, bl.EndTime,b.StartTime),0) AS DiffDT
FROM CTE AS b
LEFT OUTER JOIN CTE AS bl ON bl.Seq = b.Seq - 1 -- Last batch
ORDER BY b.StartTime
I follow this link http://blog.sqlauthority.com/2011/11/24/sql-server-solution-to-puzzle-simulate-lead-and-lag-without-using-sql-server-2012-analytic-function/
This will give you the difference in seconds.
;with cteMain as (
select *, ROW_NUMBER() over (order by Start_time) sn
from table)
select m.batch_number, sLag.End_date, m.Start_time, convert(varchar,DateAdd(Second,DATEDIFF(SECOND, sLag.End_date, m.Start_time),0),108) as time_diff
from cteMain as m LEFT OUTER JOIN cteMain AS sLag ON sLag.sn = m.sn-1
order by m.batch_number

compare next record in the same table sql

I have a table having 2 columns trans_date and amount.
I want to a query that give me the amount if the transdate diff of a record and the next record is 1 day or same day.
explanation:
AMOUNT TRANS_DATE
2645 2011-05-11 20:57:27.000
2640 2011-05-12 00:00:00.000
2645 2011-05-15 18:01:11.000
2645 2011-06-15 18:27:45.000
2645 2011-06-16 17:06:33.000
2645 2011-06-18 15:19:19.000
2645 2011-06-23 15:42:18.000
the query should show me only
AMOUNT TRANS_DATE
2645 2011-05-11 20:57:27.000
2640 2011-05-12 00:00:00.000
2645 2011-05-15 18:01:11.000
2645 2011-06-15 18:27:45.000
2645 2011-06-16 17:06:33.000
all i have tried is
select DATEDIFF(DAY,a.TRANS_DATE,b.TRANS_DATE) from FIN_AP_PAYMENTS a inner join ( select * from (select a.*,rank() over (order by id) as ra from FIN_AP_PAYMENTS a, FIN_AP_PAYMENTS b )tbl )
select a.TRANS_DATE,b.TRANS_DATE,rank() over (order by a.id) as ra1,rank() over (order by b.id) as ra2 from FIN_AP_PAYMENTS a,FIN_AP_PAYMENTS b
select DATEDIFF(day,tbl.TRANS_DATE,tbl2.TRANS_DATE) from (select a.*,rank() over (order by id) as ra from FIN_AP_PAYMENTS a) tbl inner join (select a.*,rank() over (order by a.id) as ra1 from FIN_AP_PAYMENTS a ) tbl2 on tbl.id=tbl2.id
Use lead() and lag() to get the next and previous values. Then check the timing between them for filtering:
select t.amount, t.trans_date
from (select t.*, lead(trans_date) over (order by trans_date) as next_td,
lag(trans_date) over (order by trans_date) as prev_td
from FIN_AP_PAYMENTS t
) t
where datediff(second, prev_td, trans_date) < 24*60*60 or
datediff(second, trans_date, next_trans_date) < 24*60*60;
EDIT:
In SQL Server 2008, you can do this using outer apply:
select t.amount, t.trans_date
from (select t.*, tlead.trans_date as next_td,
tlag.trans_date as prev_td
from FIN_AP_PAYMENTS t outer apply
(select top 1 t2.*
from FIN_AP_PAYMENTS t2
where t2.trans_date < t.trans_date
order by trans_date desc
) tlag outer apply
(select top 1 t2.*
from FIN_AP_PAYMENTS t2
where t2.trans_date > t.trans_date
order by trans_date asc
) tlead
) t
where datediff(second, prev_td, trans_date) < 24*60*60 or
datediff(second, trans_date, next_trans_date) < 24*60*60;
Pre SQL Server 2012 you can use a combination of ROW_NUMBER and self joins instead of LEAD and LAG.
Example
WITH Example AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY Trans_Date) AS rn,
r.*
FROM
(
VALUES
(2645, '2011-05-11 20:57:27.000'),
(2640, '2011-05-12 00:00:00.000'),
(2645, '2011-05-15 18:01:11.000'),
(2645, '2011-06-15 18:27:45.000'),
(2645, '2011-06-16 17:06:33.000'),
(2645, '2011-06-18 15:19:19.000'),
(2645, '2011-06-23 15:42:18.000')
) AS r(Amount, Trans_Date)
)
SELECT
curr.*,
FROM
Example AS curr
LEFT OUTER JOIN Example AS prv ON prv.rn = curr.rn - 1
INNER JOIN Example AS nxt ON nxt.rn = curr.rn + 1
WHERE
DATEDIFF(DAY, curr.Trans_Date, nxt.Trans_Date) IN (0, 1)
OR DATEDIFF(DAY, prv.Trans_Date, curr.Trans_Date) IN (0, 1)
;
The CTE allows you to reuse the row number multiple times. The row number provides a sequence for the self joins. The joins allow to you see the previous and next values on the same row, for comparison.
The output of this query doesn't match your example, see my question in the comments for more on this.
I'm not sure that telling people, who are giving up their time to help you, what you are / are not here to discuss is a good idea. It certainly made me think twice before posting.

SQL query to return data corresponding to all values of a column except for the min value of that column

I have a table with the following columns:
userid, datetime, type
Sample data:
userid datetime type
1 2013-08-01 08:10:00 I
1 2013-08-01 08:12:00 I
1 2013-08-01 08:12:56 I
I need to fetch data for only two rows other than the row with min(datetime)
my query to fetch data for min(datetime) is :
SELECT
USERID, MIN(CHECKTIME) as ChkTime, CHECKTYPE, COUNT(*) AS CountRows
FROM
T1
WHERE
MONTH(CONVERT(DATETIME, CHECKTIME)) = MONTH(DATEADD(MONTH, -1,
CONVERT(DATE, GETDATE())))
AND YEAR(CONVERT(DATETIME, CHECKTIME)) = YEAR(GETDATE()) AND USERID=35
AND CHECKTYPE='I'
GROUP BY
CONVERT(DATE, CHECKTIME), USERID, CHECKTYPE
HAVING
COUNT(*) > 1
a lil help'll be much appreciated..thnx
Maybe something like this will help you:
WITH CTE AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY userid ORDER BY checktime) RN
FROM dbo.T1
WHERE CHECKTYPE = 'I'
--add your conditions here
)
SELECT * FROM CTE
WHERE RN > 1
Using CTE and ROW_NUMBER() function this will select all rows except min(date) for each user.
SQLFiddle DEMO
SELECT * FROM YOURTABLE A
INNER JOIN
(SELECT USERID,TYPE,MIN(datetime) datetime FROM YOURTABLE GROUP BY USERID,TYPE )B
ON
A.USERID=B.USERID AND
A.TYPE=B.TYPE
WHERE A.DATETIME<>B.DATETIME

Sql Server Self JOIN (pushing column values down)

I am asked to do the following:
"CycleStartDate needs to be the BillDate from the previous BillDate record. If a previous record does not exist, you should use the most recent CycleEndDate from the DataTime table"
CycleStartDate and CycleEndDate are columns in a table called DataTime
BillDate is a column in a table called BillingData
This is the BillDate values:
2012-07-27 00:00:00.000
2012-07-27 00:00:00.000
2012-08-27 00:00:00.000
2012-08-27 00:00:00.000
2012-09-28 00:00:00.000
2012-09-28 00:00:00.000
2012-10-26 00:00:00.000
2012-10-26 00:00:00.000
2012-11-27 00:00:00.000
2012-11-27 00:00:00.000
2012-12-27 00:00:00.000
How would I set the CycleStartDate values based on the requirements?
The tables Datetime and BillingData are connected by a column called MeterID.
Try something similar to this...
SELECT B.BillDate,
ISNULL(
B2.BillDate,
(SELECT MAX(CycleEndDate) FROM DataTime DT WHERE DT.MeterID = B.MeterID)
) CycleStartDate
FROM BillingData B
OUTER APPLY (
SELECT TOP 1 B2.BillDate
FROM BillingData B2
WHERE B2.MeterID = B.MeterID AND
B2.BillingData < B.BillingData
ORDER BY B2.BillingData DESC
) B2
I still have one doubt... Do you need to take the SELECT MAX(CycleEndDate) FROM DataTime DT WHERE DT.MeterID = B.MeterID or the SELECT MAX(CycleEndDate) FROM DataTime DT WHERE DT.MeterID = B.MeterID AND DT.CycleEndDate < B.BillDate?
But it can be done without the OUTER APPLY...
SELECT B.BillDate,
ISNULL(
(SELECT MAX(B2.BillDate)
FROM BillingData B2
WHERE B2.MeterID = B.MeterID AND
B2.BillingData < B.BillingData),
(SELECT MAX(CycleEndDate) FROM DataTime DT WHERE DT.MeterID = B.MeterID)
) CycleStartDate
FROM BillingData B
I think the second version is quite readable... For each row of BillingData B, look for the biggest BillDate (MAX(B2.BillDate)) lesser than the current BillDate and of the same MeterID. If not present (the ISNULL, if the first one is not present then it's NULL, so it goes to the second part of the ISNULL), look for the biggest CycleEndDate from DataTime with the same MeterID and return it.
You can use the ROW_NUMBER() function for offsetting a JOIN:
SELECT a.BillDate, COALESCE(b.BillDate,c.CycleEndDate) 'CycleEndDate'
FROM (SELECT *,ROW_NUMBER() OVER (PARTITION BY MeterID ORDER BY BillDate DESC)'RowRank'
FROM YourTable
)a
LEFT JOIN (SELECT *,ROW_NUMBER() OVER (PARTITION BY MeterID ORDER BY BillDate DESC)'RowRank'
FROM YourTable
)b
ON a.RowRank = b.RowRank - 1
AND a.MeterID = b.MeterID
LEFT JOIN (SELECT MeterID,MAX(CycleEndDate)'CycleEndDate'
FROM DataTime
GROUP BY MeterID
) c
ON a.MeterID = c.MeterID
The PARTITION BY may not be necessary as well as the MeterID criteria in the JOIN, your wording is a little confusing as to whether the ORDER BY should be ascending or descending, as it is above the newest record will be the one that gets it's date from the DateTime table, remove DESC to make it the oldest record that gets it's value from that table.

TSQL- Finding the difference in days of multiple records in SQL Server

Is it possible to find the difference of days of different records in SQL Server 2008 R2?
SELECT OrderDate FROM OrdersTbl WHERE SKU='AA0000' ORDER BY ORDERDATE DESC
OrderDate
-----------------------
2009-12-03 00:00:00.000
2009-04-03 00:00:00.000
2008-02-22 00:00:00.000
2008-02-21 00:00:00.000
2007-02-18 00:00:00.000
2007-01-27 00:00:00.000
2006-10-13 00:00:00.000
I would like a way to get how many days in between there are for each order date so that I could find the average frequency. Thanks in advance.
You can do it with a common table expression and ROW_NUMBER:
WITH OrderDates AS (
SELECT
ROW_NUMBER() OVER (ORDER BY OrderDate DESC) AS RowNumber,
OrderDate
FROM OrdersTable
WHERE SKU = 'AA0000'
)
SELECT
AVG(DATEDIFF(DD, O2.OrderDate, O1.OrderDate)) AS AverageFrequency
FROM OrderDates O1
LEFT JOIN OrderDates O2
ON O2.RowNumber = O1.RowNumber + 1
Sucks there's no LEAD/LAG support in SQL Server:
SELECT z.orderdate,
z.prev_date,
DATEDIFF(dd, z.prev_date, z.orderdate)
FROM (SELECT OrderDate,
(SELECT MAX(y.orderdate)
FROM ORDERSTBL y
WHERE y.orderdate < x.orderdate
AND y.sku = x.sku) AS prev_date
FROM OrdersTbl x
WHERE x.sku ='AA0000') z
ORDER BY z.orderdate DESC
;With cteDifference as (
Select SKU, OrderDate, Row_Number() OVER (Partition by SKU Order by OrderDate) as RowNumber
from OrdersTbl
)
select cur.SKU,
cur.OrderDate as CurrentDate,
prev.OrderDate as PreviousDate,
DATEDIFF(DD,prev.OrderDate, cur.OrderDate) as DaysDifference
from cteDifference cur
left join cteDifference prev
on cur.SKU = prev.SKU
and cur.RowNumber = prev.RowNumber + 1
where cur.SKU = 'AA0000'
order by cur.OrderDate desc