【问题标题】:Can someone help me with replacing the cursor in the following SQL code有人可以帮我替换以下 SQL 代码中的光标吗
【发布时间】:2017-07-07 00:38:56
【问题描述】:

这是遍历包含各种记录的表的 SQL 代码,该表包含开始和结束数据(如缓慢变化的维度)。在检查维度时,我们发现有时开始日期不在结束日期之后。因此,我们循环表格并重新创建开始/结束日期,以确保开始/结束日期实际上是可用日期的最小/最大值。但是这个过程需要很长时间才能处理 900 万行。我很想使用 while 循环,但无法确定保留最小值/最大值并检测 ID 中的开关。

DECLARE @MINDDEB Datetime
DECLARE @DDEB Datetime
DECLARE @DFIN Datetime
DECLARE @CECV float
DECLARE @AIDNEBHNPRPEP int
DECLARE @CETA float
DECLARE @AIDNEBHNPRAFI int
DECLARE @MAXDFIN Datetime
DECLARE @OLDCECV float
DECLARE @OLDAIDNEBHNPRPEP int
DECLARE @OLDCETA float
DECLARE @OLDAIDNEBHNPRAFI int

SET @MINDDEB=9999-12-31
SET @MAXDFIN=1835-12-31
drop table dbo.TBYDWHTEBHNPRAFIVRS_CURSORTABLE
--T2
SELECT DDEB, DFIN, CETA,AIDNEBHNPRAFI 
into dbo.TBYDWHTEBHNPRAFIVRS_CURSORTABLE
FROM dbo.TBYDWHTEBHNPRAFIVRS
WHERE  AIDNEBHNPRAFI=-1
ORDER BY AIDNEBHNPRAFI,DDEB

DECLARE T2_CURSOR CURSOR FOR 
select   DDEB, DFIN, CETA,AIDNEBHNPRAFI 
from TBYDWHTEBHNPRAFIVRS
where DFIN>DDEB and BRRDDEL<>1 and CSTUVRS = 1 --and AIDNEBHNPRAFI in (1080,1033143,2311904)
order by AIDNEBHNPRAFI,DDEB,CETA,CECV


OPEN T2_CURSOR  

FETCH NEXT FROM T2_CURSOR   
INTO @DDEB,  @DFIN, @CETA,@AIDNEBHNPRAFI
SET @OLDAIDNEBHNPRAFI=@AIDNEBHNPRAFI
SET @OLDCETA=@CETA  
--SET   @OLDCECV=@CECV

WHILE @@FETCH_STATUS = 0  
BEGIN  

    if ( @OLDCETA=@CETA and @OLDAIDNEBHNPRAFI=@AIDNEBHNPRAFI) 
    BEGIN
        --print 'entering first if'
        IF (@MINDDEB>@DDEB) 
        BEGIN
            SET @MINDDEB=@DDEB
        END
        IF (@MAXDFIN<@DFIN) 
        BEGIN       
            SET @MAXDFIN=@DFIN
        END
    END
    --print ' OLD CECV '+convert(varchar(10),@OLDCECV) +' new CECV '+ convert(varchar(10),@CECV) +' OLDAID '+ convert(varchar(10),@OLDAIDNEBHNPRPEP) +' NEWAID '+ convert(varchar(10),@AIDNEBHNPRPEP)
    -- +' NEWDDEB '+ convert(varchar(10),@DDEB,101) +' MINDDEB '+ convert(varchar(10),@MINDDEB,101) +' NEWDFIn '+ convert(varchar(10),@DFIN,101) +' MAXDFIN '+ convert(varchar(10),@MAXDFIN,101)



 FETCH NEXT FROM T2_CURSOR   
    INTO   @DDEB,  @DFIN, @CETA,@AIDNEBHNPRAFI

    if ( @OLDCETA<>@CETA or @OLDAIDNEBHNPRAFI<>@AIDNEBHNPRAFI) 
    BEGIN
        INSERT INTO TBYDWHTEBHNPRAFIVRS_CURSORTABLE (DDEB, DFIN, CETA,AIDNEBHNPRAFI )
        VALUES (@MINDDEB,@MAXDFIN,@OLDCETA,@OLDAIDNEBHNPRAFI)
        SET @OLDAIDNEBHNPRAFI=@AIDNEBHNPRAFI
        --SET   @OLDCECV=@CECV
        SET @OLDCETA=@CETA
        SET @MINDDEB=@DDEB
        SET @MAXDFIN=@DFIN
    END


END   
INSERT INTO TBYDWHTEBHNPRAFIVRS_CURSORTABLE (DDEB, DFIN, CETA,AIDNEBHNPRAFI )
        VALUES (@MINDDEB,@MAXDFIN,@OLDCETA,@OLDAIDNEBHNPRAFI)
CLOSE T2_CURSOR;  
DEALLOCATE T2_CURSOR;  

这是源数据
DDEB DFIN CETA AIDNEBHNPRAFI
2006-03-01 00:00:00.000 2006-04-30 23:59:59.000 1 231272
2006-05-01 00:00:00.000 2006-11-30 23:59:59.000 1 231272
2006-12-01 00:00:00.000 2007-04-30 23:59:59.000 1 231272
2007-05-01 00:00:00.000 2008-04-30 23:59:59.000 1 231272
2008-05-01 00:00:00.000 2008-08-31 23:59:59.000 1 231272
2008-09-01 00:00:00.000 2008-10-31 23:59:59.000 2 231272
2008-11-01 00:00:00.000 2009-04-30 23:59:59.000 1 231272
2009-05-01 00:00:00.000 2010-01-31 23:59:59.000 1 231272
2010-02-01 00:00:00.000 9999-12-31 23:59:59.000 14 231272

这是我们用光标得到的结果

DDEB DFIN CETA AIDNEBHNPRAFI
2006-03-01 00:00:00.000 2008-08-31 23:59:59.000 1 231272
2008-09-01 00:00:00.000 2008-10-31 23:59:59.000 2 231272
2008-11-01 00:00:00.000 2010-01-31 23:59:59.000 1 231272
2010-02-01 00:00:00.000 9999-12-31 23:59:59.000 14 231272

【问题讨论】:

  • 要么简化和最小化问题,要么雇用某人。
  • @jarlh,你的评论对我来说似乎是广告,因为你说 或雇用某人 ... :)
  • @Rahul,但我不是这个人。
  • 这是一个很难读的时间和很长的帖子......尝试在 DECLARE T2_CURSOR CURSOR 之后使用 FAST_FORWARD 运行您的代码,并检查您是否有更好的性能
  • @Kostis,谢谢,我会试试的。

标签: sql sql-server while-loop cursor


【解决方案1】:

这是一个尝试。返回的结果匹配,但您需要使用更多数据对其进行测试。我还对数据类型做出了假设。如果您的不同,则需要相应地更新。 CTE 识别开始和停止时间没有顺序伙伴的间隔(停止和下一次启动之间相差 1 秒)。然后它为这些时间分配序列号,并根据序列连接开始和停止时间。

详细地说,2006 年 3 月 1 日的开始时间没有紧接在前的停止时间,因此它被包括在内,并且是其组的第一个开始序列。 2008 年 11 月 1 日符合相同的标准,是其组的下一个开始序列。 2008 年 8 月 31 日是第一个没有开始时间的停止时间,并且是其组的第一个停止顺序。由于 2006 年 3 月 1 日和 2008 年 8 月 31 日都是其组中的第一个序列,因此它们标记了该组第一个不间断间隔的开始和停止。

IF OBJECT_ID('tempdb..#temp') IS NOT NULL
  DROP TABLE #temp;
GO

CREATE TABLE #temp (
                     DDEB DATETIME,
                     DFIN DATETIME,
                     CETA INT,
                     AIDNEBHNPRAFI INT
                   );

INSERT INTO #temp
VALUES ('2006-03-01 00:00:00.000', '2006-04-30 23:59:59.000', '1', '231272'),
(' 2006-05-01 00:00:00.000', '2006-11-30 23:59:59.000', '1', '231272'),
(' 2006-12-01 00:00:00.000', '2007-04-30 23:59:59.000', '1', '231272'),
(' 2007-05-01 00:00:00.000', '2008-04-30 23:59:59.000', '1', '231272'),
(' 2008-05-01 00:00:00.000', '2008-08-31 23:59:59.000', '1', '231272'),
(' 2008-09-01 00:00:00.000', '2008-10-31 23:59:59.000', '2', '231272'),
(' 2008-11-01 00:00:00.000', '2009-04-30 23:59:59.000', '1', '231272'),
(' 2009-05-01 00:00:00.000', '2010-01-31 23:59:59.000', '1', '231272'),
(' 2010-02-01 00:00:00.000', '9999-12-31 23:59:59.000', '14', '231272');
WITH Starts AS (
SELECT  *, RowSeq = ROW_NUMBER() OVER(PARTITION BY ceta, t.AIDNEBHNPRAFI ORDER BY ddeb)
FROM    #temp AS t
WHERE   NOT EXISTS ( SELECT 1
                     FROM   #temp AS It
                     WHERE  t.CETA = It.CETA
                            AND t.AIDNEBHNPRAFI = It.AIDNEBHNPRAFI
                            AND It.DFIN = DATEADD(SECOND, -1, t.DDEB)
                   )
), Finishes AS (

SELECT  *, RowSeq = ROW_NUMBER() OVER(PARTITION BY ceta, t.AIDNEBHNPRAFI ORDER BY dfin)
FROM    #temp AS t
WHERE   NOT EXISTS ( SELECT 1
                     FROM   #temp AS It
                     WHERE  t.CETA = It.CETA
                            AND t.AIDNEBHNPRAFI = It.AIDNEBHNPRAFI
                            AND t.DFIN = DATEADD(SECOND, -1, it.DDEB)
                   )
)
SELECT Starts.ddeb, Finishes.DFIN,  starts.ceta, starts.AIDNEBHNPRAFI
FROM Starts
INNER JOIN Finishes
ON Starts.AIDNEBHNPRAFI = Finishes.AIDNEBHNPRAFI
AND Starts.CETA = Finishes.CETA
AND Starts.RowSeq = Finishes.RowSeq
ORDER BY Starts.ddeb

结果:

DDEB    DFIN    CETA    AIDNEBHNPRAFI

2006-03-01 00:00:00.000 2008-08-31 23:59:59.000 1   231272

2008-09-01 00:00:00.000 2008-10-31 23:59:59.000 2   231272

2008-11-01 00:00:00.000 2010-01-31 23:59:59.000 1   231272

2010-02-01 00:00:00.000 9999-12-31 23:59:59.000 14  231272

【讨论】:

    【解决方案2】:

    Wes H 让我走上了正轨。我的一位同事在代码上看了一会儿,然后想出了这个。它在 4 分 8 秒内处理了 960 万行。

    With CTETest(StartDate, EndDate, value, ID)
    AS
     (
    SELECT [DDEB], 
            Case When 
              DFIN = '9999-12-31 23:59:59.000'
              THEN
                           DFIN   
              ELSE 
                     DATEADD(SECOND, 1, [DFIN])
              END
       , [CETA]
       , [AIDNEBHNPRAFI] as ID
    FROM [dbo].[TBYDWHTEBHNPRAFIVRS]
    where DFIN>DDEB and BRRDDEL<>1 and CSTUVRS = 1 
    ),
    
    T1(ID, value, isStartTS, isEndTS, TS) 
    AS (
    SELECT ID, value, 1, 0, StartDate
    FROM CTETest
    UNION ALL
    SELECT ID, value, 0, 1, EndDate
    FROM CTETest
    ),
    
    T2 (ID, value, TS,  cr_ttl, prv_ttl) as ( 
    select ID, value, TS,
    sum(isStartTS) over (Partition by ID, value order by TS,isEndTS rows     unbounded Preceding) -
    sum(isEndTS) over (partition by ID, Value order by TS,isEndTS rows unbounded preceding)as cr_ttl, 
     sum(isStartTS) over (Partition by ID, value order by TS,isEndTS rows     between unbounded Preceding and 1 preceding ) -
    sum(isEndTS) over (partition by ID, value order by ts,isEndTS rows between     unbounded preceding and 1 preceding)as prv_ttl
    from T1 ),
    
    T3 (ID, value, TS, cr_ttl, prv_ttl) as (
    Select ID, value, TS, cr_ttl, prv_ttl
    from T2 
    where cr_ttl = 0 or prv_ttl is null or prv_ttl = 0
    ),
    
    T4 (ID, value, StartDate ,EndDate, prv_ttl) as ( 
    select ID, value, TS, 
     max(TS) over (partition by ID, value order by TS rows between current row     and 1 following),
    prv_ttl 
     from T3 
    )
    
    select ID as [AIDNEBHNPRAFI], value as CETA,StartDate as DDEB, Case When 
                  EndDate = '9999-12-31 23:59:59.000' THEN EndDate ELSE DateADD    (second, -1, EndDate) END as DFIN   
              into     [dbo].[TBYDWHTEBHNPRAFIVRS_CTE]
    from T4 
    where prv_ttl is Null or prv_ttl = 0 
    --order by ID, StartDate
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-22
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 2012-04-09
      相关资源
      最近更新 更多