Вернуть предыдущее значение перед нулевым - PullRequest
1 голос
/ 21 ноября 2019

Я сейчас запрашиваю таблицу с отсутствующими индексами.

Вот некоторые примеры данных:

id  dStartDate
126 2010-04-22 00:00:00.000
127 NULL
128 2010-04-29 00:00:00.000
129 2010-05-03 00:00:00.000
130 NULL
131 NULL
132 NULL
133 2010-04-29 00:00:00.000
134 NULL
135 NULL
136 2010-04-29 00:00:00.000
137 NULL
138 NULL
139 2010-04-29 00:00:00.000
140 NULL
141 2010-04-29 00:00:00.000
142 2010-04-29 00:00:00.000
143 NULL
144 NULL

Я использую следующий скрипт для получения отсутствующих индексов:

declare @id int
declare @maxid int

set @id = 1
select @maxid = max(idJCMaster) from _btblJCMaster

declare @IDseq table    (id int)

while @id < @maxid --whatever you max is
begin
    insert into @IDseq values(@id)

    set @id = @id + 1
end

select 
    s.id
from        @IDseq s 
left join   _btblJCMaster t on s.id = t.idJCMaster
where t.idJCMaster is null

Вышеописанное работает отлично, однако, я хотел бы видеть дату предыдущей записи (не нулевую), чтобы иметь представление, когда эта запись была удалена ...

Я изменил вышескрипт выглядит так:

declare @id int
declare @maxid int

set @id = 1
select @maxid = max(idJCMaster) from _btblJCMaster

declare @IDseq table    (id int)

while @id < @maxid --whatever you max is
begin
    insert into @IDseq values(@id)

    set @id = @id + 1
end

select 
    s.id
,   t.dStartDate
from        @IDseq s 
left join   _btblJCMaster t on s.id = t.idJCMaster

Результаты, которые я получаю, выглядят так:

Script 2 Results

Как видно, иногдадля этих конкретных индексов больше, чем в записи, пропущено ...

Я не совсем уверен, как изменить скрипт, чтобы показать мне предыдущую дату (до нуля).

В этомНапример, мои ожидаемые результаты будут:

Expected Results

Пожалуйста, помогите с ожидаемыми результатами?

Ваша помощь будет высоко ценится!

Редактировать

После помощи Анкита попробовал следующее (его ответ):

declare @id int
declare @maxid int

set @id = 1
select @maxid = max(idJCMaster) from _btblJCMaster

declare @IDseq table    (id int)

while @id < @maxid --whatever you max is
begin
    insert into @IDseq values(@id)

    set @id = @id + 1
end

select 
    s.id
,   (SELECT MAX(dStartDate)
            FROM _btblJCMaster
            WHERE id >= t1.idJCMaster) dStartDate
from        @IDseq s 
left join   _btblJCMaster t1 on s.id = t1.idJCMaster

Но я все еще получаю NULLS.

Затем я попробовал его первый ответ, немного изменив функцию LAG, а также добавив LEAD с 3 CTE, но явсе еще получите NULLS:

declare @id int
declare @maxid int

set @id = 1
select @maxid = max(idJCMaster) from _btblJCMaster

declare @IDseq table    (id int)

while @id < @maxid --whatever you max is
begin
    insert into @IDseq values(@id)

    set @id = @id + 1
end


;with cte (id, dStartDate, idJCMaster)
as
(
select 
    s.id
,   ISNULL(dStartDate, isnull(LAG(dStartDate) OVER(order by s.id),LEAD(dStartDate) OVER(order by s.id)))
,   IdJCMaster
from        @IDseq s 
left join   _btblJCMaster t1 on s.id = t1.idJCMaster
)
,   cte2 (id,dStartDate, idJCMaster)
as
(
select
    id
,   isnull(dStartDate,LAG(dStartDate) OVER(order by id))
,   idJCMaster
from    cte
)
,   cte3 (id,dStartDate, idJCMaster)
as
(
select
    id
,   isnull(dStartDate,LEAD(dStartDate) OVER(order by id))
,   idJCMaster
from    cte2
)

select
    id
,   isnull(dStartDate,LAG(dStartDate) OVER(order by id))
from    cte3
where   idJCMaster is null

Нет ли другого более простого способа сделать это?

Ответы [ 3 ]

1 голос
/ 21 ноября 2019

Вы можете попробовать кое-что по этому поводу:

Сначала нам понадобится таблица макетов , чтобы смоделировать вашу проблему. Пожалуйста, укажите это в следующем вопросе. Всегда лучше предоставить автономный самодельный образец, включая DDL, INSERT и вашу собственную попытку. Такое моделирование называется MCVE .

DECLARE @tbl TABLE(id INT,  dStartDate DATE);
INSERT INTO @tbl VALUES
 (126,'2010-04-22 00:00:00.000')
,(127,NULL)
,(128,'2010-04-29 00:00:00.000')
,(129,'2010-05-03 00:00:00.000')
,(130,NULL)
,(131,NULL)
,(132,NULL)
,(133,'2010-04-29 00:00:00.000')
,(134,NULL)
,(135,NULL)
,(136,'2010-04-29 00:00:00.000')
,(137,NULL)
,(138,NULL)
,(139,'2010-04-29 00:00:00.000')
,(140,NULL)
,(141,'2010-04-29 00:00:00.000')
,(142,'2010-04-29 00:00:00.000')
,(143,NULL)
,(144,NULL);

- запрос

WITH cte AS(SELECT id,dStartDate FROM @tbl WHERE dStartDate IS NOT NULL)
SELECT t.id 
      ,A.gaplessStartDate
FROM @tbl t
CROSS APPLY(SELECT TOP 1 cte.dStartDate 
            FROM cte 
            WHERE cte.id<=t.id 
            ORDER BY cte.id DESC) A(gaplessStartDate);

Идея вкратце:

Мы используем CTEсначала получить набор только с ненулевыми строками.
Теперь мы можем использовать APPLY, чтобы получить подходящую строку вместе с идентификатором, вызвав самый верхний из меньших идентификаторов , отсортированных по убываниюпорядок.

Подход подобен треугольника JOIN (Джефф Моден написал отличную статью на эту тему) . Любой строке потребуется коррелированный подзапрос с действием ORDER BY.

Подсказка: при большем наборе это может быть быстрее, если вы используете индексированную временную таблицу вместо CTE.

1 голос
/ 21 ноября 2019

Вы можете попробовать запрос ниже -

SELECT id, (SELECT MAX(dStartDate)
            FROM YOUR_TABLE
            WHERE id >= t1.id) dStartDate
FROM YOUR_TABLE t1;
0 голосов
/ 21 ноября 2019

Спасибо @Shnugo за вашу помощь!

С вашей помощью следующий скрипт дает мне именно то, что мне нужно, что работает с моим набором данных:

declare @id int
declare @maxid int

set @id = 1
select @maxid = max(idJCMaster) from _btblJCMaster

declare @IDseq table    (id int)

while @id < @maxid --whatever you max is
begin
    insert into @IDseq values(@id)

    set @id = @id + 1
end

;with source (id,dStartDate)
as
(
select 
    s.id
,   dStartDate
from        @IDseq s 
left join   _btblJCMaster t1 on s.id = t1.idJCMaster
)
, cte AS(SELECT id,dStartDate FROM source WHERE dStartDate IS NOT NULL)
SELECT t.id 
      ,A.gaplessStartDate
FROM source t
CROSS APPLY(SELECT TOP 1 cte.dStartDate 
            FROM cte 
            WHERE cte.id<=t.id 
            ORDER BY cte.id DESC) A(gaplessStartDate)
WHERE t.dStartDate IS NULL
order by id

Это только длядругие зрители использовать, если вам это нужно.

...