Заполнение пропущенных данных в строках без использования курсора - PullRequest
0 голосов
/ 25 сентября 2018

У меня есть таблица в этой форме (упрощенно):

CREATE TABLE [dbo].[test](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,
    [Extension] [varchar](30) NULL DEFAULT (''),
    [StartTimestamp] [datetime] NULL,
    [UserId] [varchar](30) NULL DEFAULT (''),
 CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

Рассмотрим эти данные:

Id | Extension | StartTimestamp      | UserId
------------------------------------------------
1  |  100      | 2018-09-24 16:00:00 | A 
2  |  101      | 2018-09-24 16:01:15 | B
3  |  100      | 2018-09-24 16:01:14 | 
4  |  102      | 2018-09-24 16:02:24 | C
5  |  100      | 2018-09-24 16:05:00 | A
6  |  101      | 2018-09-24 16:07:00 | B 
7  |  101      | 2018-09-24 16:30:00 |
8  |  100      | 2018-09-24 17:00:00 | D

Теперь я хочу заполнить пробелы для столбца UserId, следующего заэто правило: запись для определенного расширения и не старше 10 минут. Так что для строки с Id 3 это будет означать UserId A (как при поиске записи с Id 1).И для строки 7 UserId останется пустым, так как не сможет найти запись в течение 10 минут для этого расширения.В настоящее время я использую этот запрос для определения расширений, имеющих пробел (в сочетании с курсором):

SELECT 
  DISTINCT b.Extension
FROM test b
 INNER JOIN (
  SELECT DISTINCT Extension
   FROM test
   WHERE
    UserId = ''
   ) a ON a.Extension=b.Extension
 WHERE
  b.UserId <> ''
 ORDER BY b.Extension

Возможно ли достичь этого без использования курсора (т. Е. С помощью одного оператора обновления)?

Ответы [ 3 ]

0 голосов
/ 25 сентября 2018
with Changes as (SELECT t1.id FROM test t1 
                        CROSS APPLY 
                                    (SELECT TOP 1 t2.UserId from test  t2 where
                                                             t2.Extension = t1.extension 
                                                            and  t1.id != t2.id 
                                                            and t2.starttimestamp 
                                                              between dateadd(minute,-10,t1.starttimestamp) 
                                                              AND t2.starttimestamp 
                                                            ORDER BY t2.starttimestamp DESC) DQ
                        WHERE COALESCE(t1.userid,'') = '' 
                )
                Update Test SET UserId = 
                        (SELECT UserId from changes WHERE Changes.Id = test.Id 
                            AND EXISTS(SELECT 0 FROm Changes c2 WHERE c2.Id = test.Id)
                        )
0 голосов
/ 25 сентября 2018

Я использовал ROW_NUMBER () для достижения этой цели:

DECLARE @temp TABLE (
    [Id] [bigint] IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [Extension] [varchar](30) NULL DEFAULT (''),
    [StartTimestamp] [datetime] NULL,
    [UserId] [varchar](30) NULL DEFAULT ('')
)

INSERT INTO @temp (Extension, StartTimestamp, UserId)
SELECT 100, {ts'2018-09-24 16:00:00.000'}, 'A' UNION ALL
SELECT 101, {ts'2018-09-24 16:01:15.000'}, 'B' UNION ALL
SELECT 100, {ts'2018-09-24 16:01:14.000'}, ''  UNION ALL
SELECT 102, {ts'2018-09-24 16:02:24.000'}, 'C' UNION ALL
SELECT 100, {ts'2018-09-24 16:05:00.000'}, 'A' UNION ALL
SELECT 101, {ts'2018-09-24 16:07:00.000'}, 'B' UNION ALL
SELECT 101, {ts'2018-09-24 16:30:00.000'}, ''

SELECT
    a.Id, a.Extension, a.StartTimestamp, a.UserId, b.StartTimestamp, b.UserId
FROM @temp a
JOIN (
    SELECT
        ROW_NUMBER() OVER(PARTITION BY a.Extension ORDER BY b.StartTimestamp) RowNo,
        a.Id, a.Extension, b.StartTimestamp, b.UserId
    FROM @temp a
    JOIN @temp b ON b.Extension = a.Extension -- edited to add this
    AND LEN(b.UserId) > 0
    AND b.StartTimestamp >= DATEADD(mi, -10, a.StartTimestamp)
    AND b.StartTimestamp < DATEADD(mi, 10, a.StartTimestamp)
    WHERE a.UserId = ''
) b ON b.Id = a.Id AND b.RowNo = 1
0 голосов
/ 25 сентября 2018

Я думаю, вы можете просто использовать lag():

select t.*,
       (case when userid is not null then userid
             when (lag(StartTimestamp) over (partition by Extension 
 order by StartTimestamp) > 
                   dateadd(minute, -10, StartTimestamp)
                  )
             then lag(userid) over (partition by Extension 
 order by StartTimestamp)
        end) as imputed_userid
from test t;
...