簡體   English   中英

SQL 服務器:從同一個表中更新多個具有相同值的不同行

[英]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_startconn_end以便為每個workerclient組合找到下一行(因為可能存在具有相同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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM