[英]SQL Server: Update multiple different rows with the same value from the same table
我有一個需要使用同一個表中的值更新的表。 基本上,我想更改工作人員和客戶端相同的行中的連接設置,並且更改的行連接設置在另一個連接(具有相同的工作人員和客戶端)結束后的 5 分鍾內開始。 下面的代碼就是這樣做的。 但是還有一個問題。 當在短時間內發生多個連接時,在同一個客戶端和工作人員之間,我需要它們都具有相同的連接設置。 我真的不確定如何實現這一目標。
當前查詢:
UPDATE t
SET t.[Connection setup] = t2.[Connection setup]
FROM Table1 t
INNER JOIN Table1 t2 ON t.worker = t2.worker
AND t.client = t2.client
AND t.SessionNo <> t2.SessionNo
AND t.[Connection setup] <= DATEADD(mi, 5, t2.[Connection end])
AND t.[Connection setup] >= t2.[Connection end]
正如您在此示例中看到的那樣,同一客戶端和工作人員之間存在多個連接,並且“real_time”列顯示了它們應該擁有的時間。
SessionNo worker Tag Start Ende Dauer Connection setup Connection end client right_time
5 116590 mma 09.08.2020 00:00:00 12:44 13:01 00:17 09.08.2020 12:44:00 09.08.2020 13:01:00 OBENAT1D0137 12:44
6 106991 mma 09.08.2020 00:00:00 13:03 13:07 00:04 09.08.2020 13:03:00 09.08.2020 13:07:00 OBENAT1D0137 12:44
7 102306 mma 09.08.2020 00:00:00 13:07 13:56 00:49 09.08.2020 13:07:00 09.08.2020 13:56:00 OBENAT1D0137 12:44
8 430386 mma 09.08.2020 00:00:00 13:56 14:06 00:10 09.08.2020 13:56:00 09.08.2020 14:06:00 OBENAT1D0137 12:44
9 117264 mma 09.08.2020 00:00:00 14:06 14:17 00:10 09.08.2020 14:06:00 09.08.2020 14:17:00 OBENAT1D0137 12:44
10 434302 mma 09.08.2020 00:00:00 14:17 14:41 00:23 09.08.2020 14:17:00 09.08.2020 14:41:00 OBENAT1D0137 12:44
11 333234 mma 09.08.2020 00:00:00 14:41 14:55 00:13 09.08.2020 14:41:00 09.08.2020 14:55:00 OBENAT1D0137 12:44
12 271379 mg 09.03.2020 00:00:00 10:24 10:25 00:00 09.03.2020 10:24:00 09.03.2020 10:25:00 OBENAT1D0117 10:24
13 269650 mg 09.03.2020 00:00:00 10:25 10:47 00:21 09.03.2020 10:25:00 09.03.2020 10:47:00 OBENAT1D0117 10:24
14 290765 mg 09.03.2020 00:00:00 12:19 12:19 00:00 09.03.2020 12:19:00 09.03.2020 12:19:00 OBENAT1D0117 12:19
15 280892 mg 09.03.2020 00:00:00 12:19 12:22 00:03 09.03.2020 12:19:00 09.03.2020 12:22:00 OBENAT1D0117 12:19
對於我當前的查詢,他們只是從前一行中花費時間。 任何幫助都會很棒
編輯:我在表中添加了 4 行以更詳細地解釋問題。 例如,在最后 4 行中,客戶端和工作人員是相同的,但連接應分為 2 個不同的組。 不在一個。 從“right_time”列可以看出。
對行進行分組的一種選擇是使用遞歸。 但是,在大型數據集上遞歸可能會很慢......
樣本數據
我從您的示例數據中省略了一些列,只使用了我需要的列,並為初始值添加了一個id
列。 如果id
列不是您的數據集的一部分,那么您將不得不比較conn_start
和conn_end
以便為每個worker
和client
組合找到下一行(因為可能存在具有相同conn_start
值的行,如14
行和15
)。
create table data
(
id int,
worker nvarchar(3),
client nvarchar(15),
conn_start datetime2(0),
conn_end datetime2(0)
);
insert into data (id, worker, client, conn_start, conn_end) values
(5 , 'mma', 'OBENAT1D0137', '09.08.2020 12:44:00', '09.08.2020 13:01:00'),
(6 , 'mma', 'OBENAT1D0137', '09.08.2020 13:03:00', '09.08.2020 13:07:00'),
(7 , 'mma', 'OBENAT1D0137', '09.08.2020 13:07:00', '09.08.2020 13:56:00'),
(8 , 'mma', 'OBENAT1D0137', '09.08.2020 13:56:00', '09.08.2020 14:06:00'),
(9 , 'mma', 'OBENAT1D0137', '09.08.2020 14:06:00', '09.08.2020 14:17:00'),
(10, 'mma', 'OBENAT1D0137', '09.08.2020 14:17:00', '09.08.2020 14:41:00'),
(11, 'mma', 'OBENAT1D0137', '09.08.2020 14:41:00', '09.08.2020 14:55:00'),
(12, 'mg', 'OBENAT1D0117', '09.03.2020 10:24:00', '09.03.2020 10:25:00'),
(13, 'mg', 'OBENAT1D0117', '09.03.2020 10:25:00', '09.03.2020 10:47:00'),
(14, 'mg', 'OBENAT1D0117', '09.03.2020 12:19:00', '09.03.2020 12:19:00'),
(15, 'mg', 'OBENAT1D0117', '09.03.2020 12:19:00', '09.03.2020 12:22:00');
解決方案
如果這看起來令人生畏,那么請務必查看這個小提琴以逐步構建。
with cte as
(
select d.id,
d.worker,
d.client,
d.conn_start,
d.conn_end,
datediff(minute,
coalesce(lag(d.conn_end) over(partition by d.worker, d.client order by d.id), d.conn_start),
d.conn_start) as diff_minutes
from data d
),
rcte as
(
select c.id,
c.worker,
c.client,
c.conn_start,
c.conn_end,
c.diff_minutes,
c.conn_start as conn_start_group
from cte c
where not exists ( select 'x'
from data d2
where d2.worker = c.worker
and d2.client = c.client
and d2.id < c.id )
union all
-- select next row for each (worker, client), keep conn_start_group if difference < 5 min
select c.id,
c.worker,
c.client,
c.conn_start,
c.conn_end,
c.diff_minutes,
case
when c.diff_minutes <= 5
then r.conn_start_group
else c.conn_start
end
from rcte r
join cte c
on c.worker = r.worker
and c.client = r.client
and c.id > r.id
and not exists ( select 'x'
from cte c2
where c2.worker = c.worker
and c2.client = c.client
and c2.id > r.id
and c2.id < c.id )
)
select rc.id,
rc.worker,
rc.client,
rc.conn_start,
rc.conn_end,
rc.conn_start_group
from rcte rc
order by rc.id;
結果
id worker client conn_start conn_end conn_start_group
-- ------ ------------ ------------------- ------------------- -------------------
5 mma OBENAT1D0137 2020-09-08 12:44:00 2020-09-08 13:01:00 2020-09-08 12:44:00
6 mma OBENAT1D0137 2020-09-08 13:03:00 2020-09-08 13:07:00 2020-09-08 12:44:00
7 mma OBENAT1D0137 2020-09-08 13:07:00 2020-09-08 13:56:00 2020-09-08 12:44:00
8 mma OBENAT1D0137 2020-09-08 13:56:00 2020-09-08 14:06:00 2020-09-08 12:44:00
9 mma OBENAT1D0137 2020-09-08 14:06:00 2020-09-08 14:17:00 2020-09-08 12:44:00
10 mma OBENAT1D0137 2020-09-08 14:17:00 2020-09-08 14:41:00 2020-09-08 12:44:00
11 mma OBENAT1D0137 2020-09-08 14:41:00 2020-09-08 14:55:00 2020-09-08 12:44:00
12 mg OBENAT1D0117 2020-09-03 10:24:00 2020-09-03 10:25:00 2020-09-03 10:24:00
13 mg OBENAT1D0117 2020-09-03 10:25:00 2020-09-03 10:47:00 2020-09-03 10:24:00
14 mg OBENAT1D0117 2020-09-03 12:19:00 2020-09-03 12:19:00 2020-09-03 12:19:00
15 mg OBENAT1D0117 2020-09-03 12:19:00 2020-09-03 12:22:00 2020-09-03 12:19:00
這應該有效。 我使用了下表,因此您可能需要調整代碼以使其與您的實際表格一起使用。 [ConnSetupCalc] 列用於測試計算,而不是在測試期間更新實際數據,然后必須重新創建正確的數據。
CREATE TABLE [dbo].[conn_data](
[SessionNo] [int] NULL,
[worker] [nvarchar](3) NULL,
[client] [nvarchar](15) NULL,
[ConnectionSetup] [datetime2](0) NULL,
[ConnectionEnd] [datetime2](0) NULL,
[RightTime] [nvarchar](15) NULL,
[ConnSetupCalc] [datetime] NULL
)
此存儲過程應根據您的示例計算數據:
CREATE PROCEDURE UpdConn
AS
declare @MyCursor CURSOR;
declare @SessionNo int;
declare @Worker nvarchar(3);
declare @Client nvarchar(15);
declare @ConnStart datetime;
declare @ConnEnd datetime;
declare @Worker_prev nvarchar(3);
declare @Client_prev nvarchar(15);
declare @ConnStart_prev datetime;
declare @ConnEnd_prev datetime;
BEGIN
SET @MyCursor = CURSOR FOR
SELECT SessionNo
,worker
,client
,ConnectionSetup
,ConnectionEnd
FROM [dbo].[conn_data]
order by worker, client, ConnectionSetup
OPEN @MyCursor
FETCH NEXT FROM @MyCursor
INTO @SessionNo, @Worker, @Client, @ConnStart, @ConnEnd
WHILE @@FETCH_STATUS = 0
BEGIN
IF @Worker = @Worker_prev and @Client = @Client_prev and DATEDIFF(mi,@ConnEnd_prev,@ConnStart) between 0 and 5
BEGIN
UPDATE conn_data set ConnectionSetup = @ConnStart_prev where SessionNo = @SessionNo;
-- Test logic: UPDATE conn_data set ConnSetupCalc = @ConnStart_prev where SessionNo = @SessionNo;
END
ELSE
BEGIN
set @ConnStart_prev = @ConnStart;
END
SET @Worker_prev = @Worker;
SET @Client_prev = @Client;
SET @ConnEnd_prev = @ConnEnd;
FETCH NEXT FROM @MyCursor
INTO @SessionNo, @Worker, @Client, @ConnStart, @ConnEnd
END;
CLOSE @MyCursor ;
DEALLOCATE @MyCursor;
END;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.