SQL 替代当前使用的游标和临时表
SQL alternative to current use of cursor and temp tables
我正在清理以前的员工留下的一些存储过程,并遇到一个我试图确定是否有一种方法可以在不使用游标的情况下处理它的地方。当前,游标查看具有每条记录的开始和结束日期的临时 table。然后它获取记录的 ID,并为开始和结束日期范围内的每个日期创建一个包含 ID 和日期的行。
然后使用此数据创建另一个临时文件 table,用于存储记录的 ID 和每个 ID 的不同日期的计数。
我不能只对开始日期和结束日期之间的日期部分天做一个 datediff
吗?我觉得必须有更好的方法来获取这些信息,但我担心我可能会过度简化它并遗漏一些东西。
这是现在的代码:
declare @StartDate datetime, @EndDate datetime, @ID bigint, @WSIdAndDates cursor
set @WSIdAndDates = cursor fast_forward for
select servicestartdate, serviceenddate, WorksheetID from #que_rp_claims_dates
open @WSIdAndDates
fetch next from @WSIdAndDates into @StartDate, @EndDate, @ID
while @@FETCH_STATUS = 0
begin
with ctedaterange
as (select [Dates]=@StartDate,
@ID[workSheetid]
union ALL
select [dates] + 1,
@ID[workSheetid]
from ctedaterange
where [dates] + 1 <= @EndDate)
insert into #tempworksheetidanddates
select [workSheetid],
[dates]
from ctedaterange
option(maxrecursion 0)
fetch next from @WSIdAndDates into @StartDate, @EndDate, @ID
end
close @WSIdAndDates
deallocate @WSIdAndDates
select worksheetid, count(distinct(dates)) as LOS into ##que_rp_claims_LOS
from #tempworksheetidanddates
group by worksheetid
table ##que_rp_claims_LOS
是唯一在此代码段之外使用的代码。另一个临时 table 被丢弃。
如有任何见解或建议,我们将不胜感激。
临时 tables 的更好替代方法是使用 table 变量。您可以像这样声明一个 table 变量:
DECLARE @tempVariable table(
WorksheetID int,
servicestartdate DATE,
serviceenddate DATE
);
就游标而言,您始终可以将所有数据插入到 table 变量中,使用 while 遍历它并在处理完条目后立即将其删除。像这样:
while exists (select top 1 * from tempVariable)
begin
select top 1 @StartDate = servicestartdate, @EndDate = serviceenddate, @ID = WorksheetID from @tempVariable
//your code
DELETE TOP(1) FROM @tempVariable;
end
该进程正在从 #que_rp_claims_dates
中获取 ID 以及开始和结束日期,并为此打开一个游标。
每一行都执行相同的操作:递归 CTE 是 collecting/calculating 从开始日期到结束日期的所有日期,并将其填写在 table.
中
在最后一步,您只提供 ID 和天数。
所以我认为你是对的...如果其他任何地方都不需要你的中间结果(温度 tables),那么计算每个 ID 的 DATEDIFF
就足够了。
关注
如果使用了 DATETIME
个值,结果可能取决于实际时间(如果时间不是全天)。看这个特别仔细!
顺便说一句:感谢您为摆脱不良结构所做的努力!
我正在清理以前的员工留下的一些存储过程,并遇到一个我试图确定是否有一种方法可以在不使用游标的情况下处理它的地方。当前,游标查看具有每条记录的开始和结束日期的临时 table。然后它获取记录的 ID,并为开始和结束日期范围内的每个日期创建一个包含 ID 和日期的行。
然后使用此数据创建另一个临时文件 table,用于存储记录的 ID 和每个 ID 的不同日期的计数。
我不能只对开始日期和结束日期之间的日期部分天做一个 datediff
吗?我觉得必须有更好的方法来获取这些信息,但我担心我可能会过度简化它并遗漏一些东西。
这是现在的代码:
declare @StartDate datetime, @EndDate datetime, @ID bigint, @WSIdAndDates cursor
set @WSIdAndDates = cursor fast_forward for
select servicestartdate, serviceenddate, WorksheetID from #que_rp_claims_dates
open @WSIdAndDates
fetch next from @WSIdAndDates into @StartDate, @EndDate, @ID
while @@FETCH_STATUS = 0
begin
with ctedaterange
as (select [Dates]=@StartDate,
@ID[workSheetid]
union ALL
select [dates] + 1,
@ID[workSheetid]
from ctedaterange
where [dates] + 1 <= @EndDate)
insert into #tempworksheetidanddates
select [workSheetid],
[dates]
from ctedaterange
option(maxrecursion 0)
fetch next from @WSIdAndDates into @StartDate, @EndDate, @ID
end
close @WSIdAndDates
deallocate @WSIdAndDates
select worksheetid, count(distinct(dates)) as LOS into ##que_rp_claims_LOS
from #tempworksheetidanddates
group by worksheetid
table ##que_rp_claims_LOS
是唯一在此代码段之外使用的代码。另一个临时 table 被丢弃。
如有任何见解或建议,我们将不胜感激。
临时 tables 的更好替代方法是使用 table 变量。您可以像这样声明一个 table 变量:
DECLARE @tempVariable table(
WorksheetID int,
servicestartdate DATE,
serviceenddate DATE
);
就游标而言,您始终可以将所有数据插入到 table 变量中,使用 while 遍历它并在处理完条目后立即将其删除。像这样:
while exists (select top 1 * from tempVariable)
begin
select top 1 @StartDate = servicestartdate, @EndDate = serviceenddate, @ID = WorksheetID from @tempVariable
//your code
DELETE TOP(1) FROM @tempVariable;
end
该进程正在从 #que_rp_claims_dates
中获取 ID 以及开始和结束日期,并为此打开一个游标。
每一行都执行相同的操作:递归 CTE 是 collecting/calculating 从开始日期到结束日期的所有日期,并将其填写在 table.
中在最后一步,您只提供 ID 和天数。
所以我认为你是对的...如果其他任何地方都不需要你的中间结果(温度 tables),那么计算每个 ID 的 DATEDIFF
就足够了。
关注
如果使用了 DATETIME
个值,结果可能取决于实际时间(如果时间不是全天)。看这个特别仔细!
顺便说一句:感谢您为摆脱不良结构所做的努力!