Reputation: 686
I have a table in SQL Server 2016 that looks like this:
ID DataDate DataHour Value UpdateDate UpdateTime
23 09/03/2019 11 65.2 09/15/2019 04:15:209
16 09/03/2019 11 66.7 09/15/2019 04:15:209
26 09/03/2019 11 62.3 09/15/2019 04:15:209
27 09/03/2019 11 69.8 09/15/2019 04:15:209
15 09/03/2019 11 59.2 09/15/2019 04:15:209
22 09/02/2019 11 45.2 09/15/2019 04:15:209
41 09/02/2019 11 36.7 09/15/2019 04:15:209
25 09/02/2019 11 62.3 09/15/2019 04:15:209
21 09/02/2019 11 79.8 09/15/2019 04:15:209
12 09/02/2019 11 19.2 09/15/2019 04:15:209
17 09/02/2019 11 19.2 09/15/2019 04:15:209
I'd like to update the UpdateDate and UpdateTime columns, as follows: - Group by DataDate, DataHour - Order by ID Desc (e.g. highest first) - Leave the first row of the group as-is - For each remaining row in the group, subtract one hour from UpdateTime - If the updated UpdateTime goes to the previous day (i.e. hour = 23), decrement the UpdateDate by 1 day
Result should look like:
ID DataDate DataHour Value UpdateDate UpdateTime
23 09/03/2019 11 65.2 09/15/2019 02:15:209
16 09/03/2019 11 66.7 09/15/2019 01:15:209
26 09/03/2019 11 62.3 09/15/2019 03:15:209
27 09/03/2019 11 69.8 09/15/2019 04:15:209
15 09/03/2019 11 59.2 09/15/2019 00:15:209
22 09/02/2019 11 45.2 09/15/2019 02:15:209
41 09/02/2019 11 36.7 09/15/2019 04:15:209
25 09/02/2019 11 62.3 09/15/2019 03:15:209
21 09/02/2019 11 79.8 09/15/2019 01:15:209
12 09/02/2019 11 19.2 09/14/2019 23:15:209
17 09/02/2019 11 19.2 09/15/2019 00:15:209
Here's what I have so far:
UPDATE t
SET t.UpdateTime = DATEADD(hour,-1,g.UpdateTime), t.UpdateDate = CASE WHEN DATEPART(hour,DATEADD(hour,-1,g.UpdateTime)) = 23 THEN DATEADD(day,-1,g.UpdateDate) ELSE g.UpdateDate END
FROM mytable t
INNER JOIN (
SELECT MAX(ID) As ID, DataDate, DataHour, MAX(UpdateDate) As UpdateDate, MAX(UpdateTime) As UpdateTime
FROM mytable
GROUP BY DataDate, DataHour, ID
ORDER BY DataDate, DataHour, ID DESC
) g
ON g.id = t.id
But this is not incrementing through the group properly. Not sure if I need a window function to help with this.
Upvotes: 0
Views: 41
Reputation: 3756
Having your date and time values separated makes this difficult (as did the fact that the time was misformatted), but this should do what you want.
First, create test data:
CREATE TABLE #tmp (ID int, DataDate date, DataHour int, Value decimal(9,1), UpdateDate date, UpdateTime Time(3))
INSERT INTO #tmp Values
(23,'09/03/2019', 11, 65.2,'09/15/2019', '04:15:20.9'),
(16 ,'09/03/2019', 11 ,66.7 ,'09/15/2019', '04:15:20.9'),
(26 ,'09/03/2019', 11 ,62.3 ,'09/15/2019', '04:15:20.9'),
(27 ,'09/03/2019', 11 ,69.8 ,'09/15/2019', '04:15:20.9'),
(15 ,'09/03/2019', 11 ,59.2 ,'09/15/2019', '04:15:20.9'),
(22 ,'09/02/2019', 11 ,45.2 ,'09/15/2019', '04:15:20.9'),
(41 ,'09/02/2019', 11 ,36.7 ,'09/15/2019', '04:15:20.9'),
(25 ,'09/02/2019', 11 ,62.3 ,'09/15/2019', '04:15:20.9'),
(21 ,'09/02/2019', 11 ,79.8 ,'09/15/2019', '04:15:20.9'),
(12 ,'09/02/2019', 11 ,19.2 ,'09/15/2019', '04:15:20.9'),
(17 ,'09/02/2019', 11 ,19.2 ,'09/15/2019', '04:15:20.9')
Then here is the code that will generate the desired output. Modify this and put it into UPDATE statements as needed:
;WITH Base as (
SELECT
DataDate,
DataHour,
Max(UpdateDate) as BaseDate,
Max(UpdateTime) as BaseTime
FROM #tmp t2
GROUP BY DataDate,
DataHour
),
AdjData as (
SELECT
ID,
t.DataDate,
t.DataHour,
t.Value,
Cast(BaseDate as Datetime) + Cast(BaseTime as DateTime) as BaseDateTime
,row_number() over (Partition by t.DataDate, t.DataHour ORDER BY t.Id Desc) as Adj
FROM #tmp t
INNER JOIN Base b
ON t.DataDate = b.DataDate
AND t.DataHour = b.DataHour
)
SELECT Id,
DataDate,
DataHour,
Value,
Cast(Dateadd(hour, -(Adj-1), BaseDateTime) AS date) as UpdateDate,
Cast(Dateadd(hour, -(Adj-1), BaseDateTime) AS Time(3)) as UpdateTime
FROM AdjData
Upvotes: 1