使用增量值更新组
Updating a group by with incrementing values
我在 SQL Server 2016 中有一个 table,如下所示:
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
我想更新 UpdateDate 和 UpdateTime 列,如下所示:
- 按 DataDate、DataHour 分组
- 按 ID Desc 排序(例如,最高优先)
- 保持组的第一行不变
- 对于组中剩余的每一行,从 UpdateTime 中减去一小时
- 如果更新的 UpdateTime 转到前一天(即小时 = 23),则将 UpdateDate 减少 1 天
结果应如下所示:
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
这是我目前的情况:
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
但这并没有正确地在整个组中递增。不确定我是否需要 window 函数来帮助解决这个问题。
将日期和时间值分开会使这变得困难(时间格式错误也是如此),但这应该可以满足您的要求。
首先,创建测试数据:
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')
下面是将生成所需输出的代码。修改它并根据需要将其放入 UPDATE 语句中:
;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
我在 SQL Server 2016 中有一个 table,如下所示:
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
我想更新 UpdateDate 和 UpdateTime 列,如下所示: - 按 DataDate、DataHour 分组 - 按 ID Desc 排序(例如,最高优先) - 保持组的第一行不变 - 对于组中剩余的每一行,从 UpdateTime 中减去一小时 - 如果更新的 UpdateTime 转到前一天(即小时 = 23),则将 UpdateDate 减少 1 天
结果应如下所示:
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
这是我目前的情况:
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
但这并没有正确地在整个组中递增。不确定我是否需要 window 函数来帮助解决这个问题。
将日期和时间值分开会使这变得困难(时间格式错误也是如此),但这应该可以满足您的要求。
首先,创建测试数据:
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')
下面是将生成所需输出的代码。修改它并根据需要将其放入 UPDATE 语句中:
;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