首页 > 解决方案 > 虽然循环 SQL 没有填充完整的结果

问题描述

问题:迭代只发生到记录 131 并给出准确的值,之后参数@ADE_END_DATE返回一个NULL值,为什么会这样?下面是我的代码。

此外,我注意到该列Leave_Date具有NULL值,并且迭代停止并为@ADE_END_DATENULL 值开始的参数返回 NULL 值。

谢谢你的帮助。

BEGIN
    DECLARE @HIREDATEPlus1Yr DATETIME
    DECLARE @ADE_Leave_Date DATETIME
    DECLARE @ADE_End_Date DATETIME
    DECLARE @ADE_Start_Date DATETIME
    DECLARE @DATECAL DATETIME
    DECLARE @i INT
    DECLARE @j INT
    DECLARE @Loop_length INT
    DECLARE @ID VARCHAR(18)

    -- start of loop
    SET @j = 1

    -- Loop length will equal to the list of all ADRs
    SET @Loop_Length = (SELECT COUNT([AD_ID]) 
                        FROM [DS_ADHOC_MOPs].[ADE].[List] 
                        WHERE Status NOT IN ('MANAGER', 'TBH', 'FROZEN'))

    -- Loop through each ADRs
    WHILE (@j <= @Loop_length)
    BEGIN
        -- Loop through each ADRs
        SET @i = 0

        -- Find AD ID
        SET @ID = (SELECT TOP 1 [AD_ID] FROM [DS_ADHOC_MOPs].[ADE].[List] 
                   WHERE [AD_ID] NOT IN (SELECT TOP (@j-1) [AD_ID] 
                                         FROM [DS_ADHOC_MOPs].[ADE].[List] 
                                         WHERE ([AD_ID] IS NOT NULL 
                                           AND Status NOT IN ('MANAGER', 'TBH', 'FROZEN')))) 

        -- Find the start date of the ADR
        SET @ADE_Start_Date = (SELECT TOP 1 [Hire_Date] 
                               FROM [DS_ADHOC_MOPs].[ADE].[List] 
                               WHERE [AD_ID] NOT IN (SELECT TOP (@j-1) [AD_ID] 
                                                     FROM [DS_ADHOC_MOPs].[ADE].[List] 
                                                     WHERE ([AD_ID] IS NOT NULL 
                                                       AND Status NOT IN ('MANAGER', 'TBH', 'FROZEN')))) 

        -- Hire date plus 1 year
        SET @HIREDATEPlus1Yr = DATEADD(YEAR, 1, @ADE_Start_Date)

        --Adding Leave Date
        SET @ADE_Leave_Date = (SELECT TOP 1 [LEAVE_DATE] 
                               FROM [DS_ADHOC_MOPs].[ADE].[List] 
                               WHERE [AD_ID] NOT IN (SELECT TOP (@j-1) [AD_ID] 
                                                     FROM [DS_ADHOC_MOPs].[ADE].[List] 
                                                     WHERE ([AD_ID] IS NOT NULL 
                                                       AND Status NOT IN ('MANAGER', 'TBH', 'FROZEN'))))  

        
     -- Set a temporary variable which will be 1 year from now. Use the Date ADD formulae to start date, if they are leaver before one year then add leave date (Use IF): DONE
     -- Put everything inside the while loop and add opportunity selecting to it. 

    IF  @ADE_Leave_Date IS NULL 
        SET @ADE_End_Date = DATEADD(YEAR, 1, @ADE_Start_Date)
    ELSE IF @HIREDATEPlus1Yr < @ADE_Leave_Date
        SET @ADE_End_Date = DATEADD(YEAR, 1, @ADE_Start_Date)
    ELSE  
        SET @ADE_End_Date = @ADE_Leave_Date
    
    SET @DATECAL = datediff(DAY, @ADE_Start_Date, @ADE_End_Date)
     
    SET @j = @j + 1

    UPDATE #TEMPTABLEEEE 
    SET [@ADE_End_Date] = @ADE_End_Date
    WHERE @ID = AD_ID
END

SELECT * FROM #TEMPTABLEEEE
END

标签: sqlsql-serverwhile-loop

解决方案


我不确定你为什么使用 WHILE 循环。看起来这段代码可以大大简化。SQL 是一种基于集合的语言。只要有可能,您应该尝试将数据作为一个整体来处理,而不是将其分解为逐行评估。

这能满足你的需要吗?如果表中的每个 AD_ID 有多于一行,则需要获取 MAX() 或 MIN() Hire_Date/LEAVE_DATE。要改进答案,请考虑提供示例数据。

UPDATE t
SET     [@ADE_End_Date] = ed.ADE_EndDate
FROM    #TEMPTABLEEEE AS t
        INNER JOIN (
                        SELECT  AD_ID
                                ,CASE
                                    WHEN LEAVE_DATE IS NULL THEN DATEADD(YEAR,1,Hire_Date)
                                    WHEN DATEADD(YEAR,1,Hire_Date) < LEAVE_DATE THEN  DATEADD(YEAR,1,Hire_Date)
                                    ELSE LEAVE_DATE
                                END AS ADE_EndDate
                        FROM    DS_ADHOC_MOPs.ADE.List
                        WHERE   Status NOT IN ('MANAGER', 'TBH', 'FROZEN')
                    ) AS ed ON t.AD_ID = ed.AD_ID

推荐阅读