Return 空值之前的前一个值
Return previous value before null value
我目前正在查询缺少索引的 table。
这是一些示例数据:
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
我得到的结果如下所示:
可以看出,对于那些特定的索引,有时会丢失比记录更多的内容...
我不太确定如何更改脚本以显示上一个日期(空之前)。
在这个例子中,我的预期结果是:
请协助预期结果?
非常感谢您的帮助!
编辑
在Ankit的帮助下,尝试了以下(他的回答):
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
没有其他更简单的方法来完成这个吗?
您可以尝试以下查询 -
SELECT id, (SELECT MAX(dStartDate)
FROM YOUR_TABLE
WHERE id >= t1.id) dStartDate
FROM YOUR_TABLE t1;
你可以试试这个:
首先我们需要一个 模型 table 来模拟您的问题。请在下一个问题中自行提供。始终最好提供一个 self-运行、独立 示例,包括 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
通过调用按降序排序的 较小的 ids 的最顶部来获取合适的行和 id。
这种方法有点像 triangle JOIN (Jeff Moden wrote a great article on this)。任何行都需要一个带有 ORDER BY 操作的相关子查询。
提示:如果您使用索引温度 table 而不是 CTE,则使用更大的集合可能会更快。
感谢@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
这仅供其他观众使用,如果您需要的话。
我目前正在查询缺少索引的 table。
这是一些示例数据:
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
我得到的结果如下所示:
可以看出,对于那些特定的索引,有时会丢失比记录更多的内容...
我不太确定如何更改脚本以显示上一个日期(空之前)。
在这个例子中,我的预期结果是:
请协助预期结果?
非常感谢您的帮助!
编辑
在Ankit的帮助下,尝试了以下(他的回答):
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
没有其他更简单的方法来完成这个吗?
您可以尝试以下查询 -
SELECT id, (SELECT MAX(dStartDate)
FROM YOUR_TABLE
WHERE id >= t1.id) dStartDate
FROM YOUR_TABLE t1;
你可以试试这个:
首先我们需要一个 模型 table 来模拟您的问题。请在下一个问题中自行提供。始终最好提供一个 self-运行、独立 示例,包括 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
通过调用按降序排序的 较小的 ids 的最顶部来获取合适的行和 id。
这种方法有点像 triangle JOIN (Jeff Moden wrote a great article on this)。任何行都需要一个带有 ORDER BY 操作的相关子查询。
提示:如果您使用索引温度 table 而不是 CTE,则使用更大的集合可能会更快。
感谢@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
这仅供其他观众使用,如果您需要的话。