避免SQL Server中的游标
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了避免SQL Server中的游标相关的知识,希望对你有一定的参考价值。
我试图避免光标从当前格式获得以下所需的输出。目前我必须使用光标,因为数据集非常庞大,我需要大约2个小时来运行它。有没有办法避免光标
Declare @CustomerId CHAR(8)
Declare @StartDate DateTime
Declare @PlStartDate DateTime
Declare @ProviderNo CHAR(8)
Declare @Code CHAR(3)
Declare @PreviousCustomerId CHAR(8)
Declare @PreviousStartDate DateTime
Declare @PreviousRealStartDate DateTime
Declare @PreviousProviderNo CHAR(8)
Declare @PreviousCode CHAR(3)
Declare @RowNumber smallint
Declare @providers CURSOR
SET @providers = CURSOR FAST_FORWARD FOR
Select CustomerId, StartDate, PlStartDate, ProviderNo, Code, ProviderSSN, RowNumber
From dbo.[provider] ORDER by CustomerId, StartDate
OPEN @providers
FETCH NEXT From @providers INTO @CustomerId, @StartDate, @PlStartDate,@ProviderNo, @Code, @ProviderSSN, @RowNumber
WHILE @@FETCH_STATUS = 0
BEGIN
If @RowNumber <>1 AND @CustomerId = @PreviousCustomerId AND @Code = @PreviousCode AND (@ProviderNo = @PreviousProviderNo)
BEGIN
Update dbo.provider
SET StartDate = @PreviousRealStartDate
Where CustomerId = @CustomerId AND StartDate = @StartDate;
END
ELSE
BEGIN
Set @StartDate = @StartDate;
Update dbo.provider
Set StartDate = @StartDate
Where CustomerId = @CustomerId AND StartDate = @StartDate
END
Set @PreviousCustomerId = @CustomerId
Set @PreviousCode = @Code
Set @PreviousProviderNo = @ProviderNo
if @StartDate IS NOT NULL
Set @PreviousRealStartDate = @StartDate
Set @PreviousStartDate = @StartDate
FETCH NEXT From @providers INTO @CustomerId, @StartDate, @PlStartDate,@ProviderNo, @Code, @RowNumber
END
CLOSE @providers
DEALLOCATE @providers
当前格式
Cust ID Start Date End Date Code Provider 7063903 2/11/2009 2/17/2009 DEF 485960 7063903 2/17/2009 2/24/2009 DEF 485960 7063903 2/24/2009 4/6/2009 LHF 479407 7063903 4/6/2009 9/11/2009 DEF 487398 7063903 8/31/2010 9/1/2010 DEF 487398 7063903 8/28/2011 11/25/2011 ABC 531428 7063903 3/1/2012 6/25/2012 DEF 487398 7063903 6/25/2012 3/22/2013 DEF 487398 7063903 3/22/2013 4/23/2014 DEF 487398 7063903 4/23/2014 5/1/2014 DEF 487398 7063903 5/1/2014 7/1/2015 DEF 487398 7063903 7/1/2015 8/28/2015 DEF 531428 7063903 8/28/2015 11/25/2015 ABC 531428 7063903 11/25/2015 9/21/2016 ABC 531428 Desired Output CustID Start Date End Date Code Provider 7063903 2/11/2009 2/24/2009 DEF 485960 7063903 2/24/2009 4/6/2009 LHF 479407 7063903 4/6/2009 9/1/2010 DEF 487398 7063903 8/28/2011 11/25/2011 ABC 531428 7063903 4/6/2009 7/1/2015 DEF 487398 7063903 7/1/2015 8/28/2015 DEF 531428 7063903 8/28/2015 9/21/2016 ABC 531428
答案
SELECT customer
, code
, provider
, MIN (start_date) start_date
, MAX (end_date) end_date
FROM dbo.provider
GROUP BY customer, code, provider;
如下所述重复提供者时,此解决方案失败。看看红色箭头:
汤姆,
我必须道歉,我误解了原来的问题。您希望将答案分组在客户/代码/提供商相同的位置,并且开始日期=上一个结束日期。
下面的SQL通过在客户/代码/提供者不匹配时设置值1,或者开始日期不等于上一个结束日期来执行此操作。然后,我将之前记录中的所有1的总和相加,以创建我可以分组的值。然后我按原始答案执行最小/最大,这次包括小组。
我得到了你所要求的相同答案,但有一个例外。您的第一个箭头应该是两行,而不是一行。请试一试。
谢谢,
布赖恩
WITH
aset
AS
(SELECT customer
, code
, provider
, start_date
, end_date
, CASE
WHEN LAG (customer)
OVER (
PARTITION BY customer, code, provider ORDER BY end_date
) = customer
AND LAG (provider)
OVER (
PARTITION BY customer, code, provider ORDER BY end_date
) = provider
AND LAG (code)
OVER (
PARTITION BY customer, code, provider ORDER BY end_date
) = code
AND LAG (end_date)
OVER (
PARTITION BY customer, code, provider ORDER BY end_date
) = start_date
THEN
0
ELSE
1
END
flag
FROM deleteme_tbl),
bset
AS
(SELECT customer
, code
, provider
, flag
, start_date
, end_date
, SUM (flag)
OVER (
ORDER BY
customer
, code
, provider
, start_date
RANGE UNBOUNDED PRECEDING
)
grp
FROM aset)
SELECT customer
, code
, provider
, MIN (start_date) start_date
, MAX (end_date) end_date
FROM bset
GROUP BY customer
, code
, provider
, grp
ORDER BY customer
, code
, provider
, start_date;
另一答案
是的,改为使用窗口函数,考虑使用LAG()
Select
CustomerId
, StartDate
, PlStartDate
, ProviderNo
, Code
, ProviderSSN
, RowNumber
, LAG(StartDate) OVER(PARTITION BY CustomerId, Code, ProviderNo
ORDER by StartDate) as lag_date
From dbo.[provider]
WHERE StartDate IS NULL
ORDER by CustomerId, StartDate
如果这是正确的,您可以将其用于公用表表达式,然后使用它进行更新。不过先测试一下小东西。例如
with cte as ( query shown above )
update cte
set StartDate = lag_date
以上是关于避免SQL Server中的游标的主要内容,如果未能解决你的问题,请参考以下文章