首页 > 解决方案 > 带有 CTE 的案例语句(条件)

问题描述

我有一个我正在尝试转换为 TVF 的功能。但我面临的问题是,该功能是多方的,具有多个 IF 条件。

我能够将一种条件转换为 TVF,为此我使用了 CTE。(我之前从这个论坛获得了帮助)。但是当我试图通过包含条件语句将整个函数转换为 TVF 时,我遇到了麻烦。

CREATE FUNCTION [dbo].[GetEventDecisionDueDate]
(
       @EventNumber VARCHAR(20),
       @BaseId VARCHAR(25),
          @CheckDate BIT
)

RETURNS DateTime
AS
BEGIN

DECLARE @CurrentStatus VARCHAR(20)
DECLARE @BaseDateTime DateTime
DECLARE @DecisionDueDate DateTime


SELECT @CurrentStatus = (SELECT cis.IncidentStatus
                                 FROM CurrentStatus cis 
                                 INNER JOIN Base r WITH (NOLOCK) ON (cis.BaseId = r.Id)
                                 WHERE (r.EventNumber = @EventNumber) AND r.BaseId = @BaseId)

SELECT @BaseDateTime = (SELECT BaseDateTime FROM Base r 
                          WHERE (r.EventNumber = @EventNumber) AND r.BaseId = @BaseId)

IF @CurrentStatus IN ('0','6') AND @CheckDate = 1
BEGIN

       SET @DecisionDueDate = DATEADD(DAY, 30, @BaseDateTime)

       WHILE @DecisionDueDate < getdate() 
             SET @DecisionDueDate = DATEADD(DAY, 30, @DecisionDueDate)

       DECLARE @FinalJournalDate DateTime

       SELECT @FinalJournalDate = (SELECT TOP 1 ij.Date
                                       FROM EventDetails_Journal ij 
                                       INNER JOIN EventJournal p ON ij.PageId = p.Id 
                                       INNER JOIN Journal f ON p.JournalId = f.Id 
                                       INNER JOIN Base r WITH (NOLOCK) ON (f.BaseId = r.Id)
                                       WHERE (r.EventNumber = @EventNumber AND r.BaseId = @BaseId) AND ij.ReviewType = 'Supervisor Monthly Review' ORDER BY ij.Date DESC)

      IF(DATEADD(DAY, 30, @BaseDateTime) < getdate() AND
           (@FinalJournalDate is null OR DATEADD(DAY, 30, @FinalJournalDate) < getdate()) AND
              DATEADD(DAY, 14, @DecisionDueDate) > DATEADD(DAY, 30, getdate()))
                  SET @DecisionDueDate = DATEADD(DAY, -30, @DecisionDueDate)
         ELSE IF((@FinalJournalDate is not null ) AND (DATEADD(DAY, 30, @FinalJournalDate) >= @DecisionDueDate))
                  SET @DecisionDueDate = DATEADD(DAY, 30, @DecisionDueDate)

END


IF @CurrentStatus IN ('0','6') AND @CheckDate = 0
BEGIN

       SET @DecisionDueDate = DATEADD(DAY, 30, @BaseDateTime)

       WHILE @DecisionDueDate < getdate() 
             SET @DecisionDueDate = DATEADD(DAY, 30, @DecisionDueDate)

       DECLARE @Final30DayDecisonDate DateTime
       DECLARE @Final6MonthDecisonDate DateTime
       DECLARE @Final30DayJournalDate DateTime

       SELECT @Final30DayDecisonDate = (SELECT TOP 1  idps.BaseSupplementDate
                                                FROM EventDetails_Supplements idps 
                                                INNER JOIN EventDetails p ON idps.PageId = p.Id 
                                                INNER JOIN Journal f ON p.JournalId = f.Id 
                                                INNER JOIN Base r WITH (NOLOCK) ON (f.BaseId = r.Id)
                                                WHERE (r.EventNumber = @EventNumber) AND 
                                                             r.BaseId = @BaseId AND idps.IsThirtyDayReview = 1 ORDER BY idps.BaseSupplementDate DESC)

       SELECT @Final6MonthDecisonDate = (SELECT TOP 1  idps.BaseSupplementDate
                                                FROM EventDetails_Supplements idps 
                                                INNER JOIN EventDetails p ON idps.PageId = p.Id 
                                                INNER JOIN Journal f ON p.JournalId = f.Id 
                                                INNER JOIN Base r WITH (NOLOCK) ON (f.BaseId = r.Id)
                                                WHERE (r.EventNumber = @EventNumber) AND 
                                                             r.BaseId = @BaseId AND idps.IsSixMonthReview = 1 ORDER BY idps.BaseSupplementDate DESC)

       SELECT @Final30DayJournalDate = (SELECT TOP 1 ij.Date
                                       FROM EventDetails_Journal ij 
                                       INNER JOIN EventJournal p ON ij.PageId = p.Id 
                                       INNER JOIN Journal f ON p.JournalId = f.Id 
                                       INNER JOIN Base r WITH (NOLOCK) ON (f.BaseId = r.Id)
                                       WHERE (r.EventNumber = @EventNumber AND r.BaseId = @BaseId) AND ij.ReviewType = '30-DAY' ORDER BY ij.Date DESC)

      IF(DATEADD(DAY, 30, @BaseDateTime) < getdate() AND
           (@Final30DayJournalDate is null OR DATEADD(DAY, 30, @Final30DayJournalDate) < getdate()) AND
           (@Final30DayDecisonDate is null OR DATEADD(DAY, 30, @Final30DayDecisonDate) < getdate()) AND
           (@Final6MonthDecisonDate is null OR DATEADD(DAY, 30, @Final6MonthDecisonDate) < getdate()) AND
              DATEADD(DAY, 14, @DecisionDueDate) > DATEADD(DAY, 30, getdate()))
                  SET @DecisionDueDate = DATEADD(DAY, -30, @DecisionDueDate)
      ELSE
         BEGIN
              IF((@Final30DayJournalDate is not null ) AND (DATEADD(DAY, 30, @Final30DayJournalDate) >= @DecisionDueDate))
                  SET @DecisionDueDate = DATEADD(DAY, 30, @DecisionDueDate)

              IF((@Final30DayDecisonDate is not null ) AND (DATEADD(DAY, 30, @Final30DayDecisonDate) >= @DecisionDueDate))
            SET @DecisionDueDate = DATEADD(DAY, 30, @DecisionDueDate)

              IF((@Final6MonthDecisonDate is not null ) AND (DATEADD(DAY, 30, @Final6MonthDecisonDate) >= @DecisionDueDate))
                 SET @DecisionDueDate = DATEADD(MONTH, 6, @DecisionDueDate)
      END          
END
ELSE IF @CurrentStatus = '4' AND @CheckDate = 0
BEGIN

   DECLARE @InactiveBaseSupplementDate DateTime
   DECLARE @LastInactiveBaseSupplementDate DateTime
   DECLARE @LastInactiveJournalDate DateTime

   SELECT @InactiveBaseSupplementDate = (SELECT TOP 1  idps.BaseSupplementDate
                                              FROM EventDetails_Supplements idps 
                                              INNER JOIN EventDetails p ON idps.PageId = p.Id 
                                              INNER JOIN IncidentDetailsPage_Incident idp ON idps.PageId = p.Id 
                                              INNER JOIN Journal f ON p.JournalId = f.Id 
                                              INNER JOIN Base r WITH (NOLOCK) ON (f.BaseId = r.Id)
                                              WHERE (r.EventNumber = @EventNumber) AND 
                                                             r.BaseId = @BaseId AND idp.IncidentStatus = '4' ORDER BY idps.BaseSupplementDate ASC)

        SET @DecisionDueDate = DATEADD(Month, 6, @InactiveBaseSupplementDate)

           WHILE @DecisionDueDate < getdate() 
             SET @DecisionDueDate = DATEADD(Month, 6, @DecisionDueDate)



        SELECT @LastInactiveBaseSupplementDate = (SELECT TOP 1  idps.BaseSupplementDate
                                              FROM EventDetails_Supplements idps 
                                              INNER JOIN EventDetails p ON idps.PageId = p.Id 
                                              INNER JOIN IncidentDetailsPage_Incident idp ON idps.PageId = p.Id 
                                              INNER JOIN Journal f ON p.JournalId = f.Id 
                                              INNER JOIN Base r WITH (NOLOCK) ON (f.BaseId = r.Id)
                                              WHERE (r.EventNumber = @EventNumber) AND 
                                                             r.BaseId = @BaseId AND idp.IncidentStatus = '4' AND idps.IsInactiveReview = 1 ORDER BY idps.BaseSupplementDate DESC)

        SELECT @LastInactiveJournalDate = (SELECT TOP 1 ij.Date
                                              FROM EventDetails_Journal ij 
                                              INNER JOIN EventJournal p ON ij.PageId = p.Id 
                                              INNER JOIN Journal f ON p.JournalId = f.Id
                                              INNER JOIN Base r WITH (NOLOCK) ON (f.BaseId = r.Id)
                                              WHERE (r.EventNumber = @EventNumber) AND 
                                              r.BaseId = @BaseId AND  ij.ReviewType = 'Inactive' ORDER BY ij.Date DESC)

      IF(DATEADD(MONTH, 6, @InactiveBaseSupplementDate) < getdate() AND
           (@LastInactiveJournalDate is null OR DATEADD(MONTH, 6, @LastInactiveBaseSupplementDate) < getdate()) AND
           (@LastInactiveBaseSupplementDate is null OR DATEADD(MONTH, 6, @LastInactiveJournalDate) < getdate()) AND
              DATEADD(DAY, 14, @DecisionDueDate) > DATEADD(MONTH, 6, getdate()))
                  SET @DecisionDueDate = DATEADD(Month, -6, @DecisionDueDate)
      ELSE
         BEGIN
              if((@LastInactiveBaseSupplementDate is not null ) AND (DATEADD(Month, 6, @LastInactiveBaseSupplementDate) >= @DecisionDueDate))
                       SET @DecisionDueDate = DATEADD(Month, 6, @DecisionDueDate)

              if((@LastInactiveJournalDate is not null ) AND (DATEADD(Month, 6, @LastInactiveJournalDate) >= @DecisionDueDate))
                       SET @DecisionDueDate = DATEADD(Month, 6, @DecisionDueDate)          
         END
END

END


GO

如您所见,我有多个 if 条件,并且我能够转换一个 if 条件,如下所示。我用条件转换了第一部分 IF @CurrentStatus IN ('0','6') AND @CheckDate = 1

CREATE FUNCTION [dbo].[GetEventDecisionDueDate_test1]
(
       @EventNumber VARCHAR(20),
       @AgencyOri VARCHAR(25),
          @CheckDate BIT
)

RETURNS TABLE 
AS
    RETURN
     WITH X 
          AS (SELECT cis.IncidentStatus AS CurrentIncidentStatus,
                     r.BaseDateTime,
                     FROM CurrentIncidentStatus cis 
                     INNER JOIN Base r WITH (NOLOCK) ON (cis.BaseId = r.Id)
                     WHERE (r.EventNumber = @EventNumber) AND r.AgencyOri = @AgencyOri
                     AND cis.IncidentStatus IN ('0','6')
                     AND @CheckDate = 1)
    SELECT X.CurrentIncidentStatus,
           X.BaseDateTime,
           CA4.DecisionDueDate
    FROM X
    CROSS APPLY (VALUES(DATEADD(DAY, 30, X.BaseDateTime))) CA1(DecisionDueDate)
    CROSS APPLY (VALUES(DATEADD(DAY, 30 * CEILING(( IIF(CAST(GETDATE() AS TIME) > CAST(CA1.DecisionDueDate AS TIME), 1, 0)
                                                    + DATEDIFF(DAY, CA1.DecisionDueDate, GETDATE()) ) / 30.0), CA1.DecisionDueDate))) CA2(DecisionDueDate)
    CROSS APPLY (SELECT TOP 1 ij.Date
                                       FROM EventDetails_Journal ij 
                                       INNER JOIN EventJournal p ON ij.PageId = p.Id 
                                       INNER JOIN Journal f ON p.JournalId = f.Id 
                                       INNER JOIN Base r WITH (NOLOCK) ON (f.BaseId = r.Id)
                                       WHERE (r.EventNumber = @EventNumber AND r.AgencyOri = @AgencyOri) AND 
                                       ij.ReviewType = 'Supervisor Monthly Review' ORDER BY ij.Date DESC) CA3(IncidentJournalDate)
    CROSS APPLY (VALUES ( CASE
                          WHEN ( DATEADD(DAY, 30, X.BaseDateTime) < GETDATE()
                                 AND ( CA3.IncidentJournalDate IS NULL
                                        OR DATEADD(DAY, 30, CA3.IncidentJournalDate) < GETDATE() )
                                 AND DATEADD(DAY, 14, CA2.DecisionDueDate) > DATEADD(DAY, 30, GETDATE()) )
                            THEN DATEADD(DAY, -30, CA2.DecisionDueDate)
                          WHEN( ( CA3.IncidentJournalDate IS NOT NULL )
                                AND ( DATEADD(DAY, 30, CA3.IncidentJournalDate) >= CA2.DecisionDueDate ) )
                            THEN DATEADD(DAY, 30, CA2.DecisionDueDate)
                          ELSE CA2.DecisionDueDate
                        END )) CA4(DecisionDueDate); 
GO

我会尽量让它简单。如果有人可以帮助我,将所有条件逻辑包含在一个有用的函数中。

标签: sql-serverfunctionconditional-statementscommon-table-expression

解决方案


您可以使用以下方法对第二部分执行相同的转换UNION ALL

SELECT *
FROM (-- all nested logic here
     )
WHERE @CurrentStatus IN ('0','6') AND @CheckDate = 1
UNION ALL
SELECT *
FROM (-- rest of nested logic here
     )
WHERE @CurrentStatus = '4' AND @CheckDate = 0

推荐阅读