2014-10-28 41 views
1

我有一个包含四个datetime列的预约表中返回多个值未来,在过去,所有的表演。 AppointmentEnd甚至被发现在AppointmentStart之前。如何从存储过程的T-SQL查询

我写了一个存储过程来计算开始和结束时间以及约会的长度。

ALTER PROCEDURE Calcdates @ApptStart DATETIME, 
          @ApptEnd DATETIME, 
          @PatArrive DATETIME, 
          @PatDepart DATETIME 
AS 
    DECLARE @CalcStart DATETIME 
    DECLARE @CalcEnd DATETIME 
    DECLARE @CalcLen INT 

    -- CALCULATED STARTDATETIME 
    SET @CalcStart = CASE 
         WHEN @PatArrive IS NULL THEN @ApptStart 
         WHEN @PatArrive IS NOT NULL THEN 
         CASE 
          WHEN @PatArrive BETWEEN Dateadd(MINUTE, -60, @ApptStart) AND Dateadd(MINUTE, 480, @ApptStart) THEN @PatArrive 
          ELSE @ApptStart 
         END 
        END 
    -- CALCUALTED ENDDATETIME 
    SET @CalcEnd = CASE 
        WHEN @PatDepart IS NULL THEN 
         CASE 
         WHEN @ApptEnd BETWEEN @ApptStart AND Dateadd(MINUTE, 480, @ApptStart) THEN @ApptEnd 
         ELSE Dateadd(MINUTE, 30, @ApptStart) 
         END 
        WHEN @PatDepart IS NOT NULL THEN 
         CASE 
         WHEN @PatDepart BETWEEN @ApptStart AND Dateadd(MINUTE, 480, @ApptStart) THEN @PatDepart 
         ELSE 
          CASE 
          WHEN @ApptEnd BETWEEN @ApptStart AND Dateadd(MINUTE, 480, @ApptStart) THEN @ApptEnd 
          ELSE Dateadd(MINUTE, 30, @ApptStart) 
          END 
         END 
        END 
    -- CALCULATED LENGTH 
    SET @CalcLen = Datediff(MINUTE, @CalcStart, @CalcEnd) 

我现在需要做的是弄清楚如何在我的查询中有这个返回值。

即这是我目前有

SELECT PrimKey, 
     Name, 
     AppointmentStart, 
     AppointmentEnd, 
     PatArrive, 
     PatDepart, 
     Somehow have the results of the SP here 
FROM MyTable 

我想要做的就是调用查询中的SP,并给我的计算值对于每个记录。

有人知道如何做到这一点吗?或者我是否以错误的方式去做?

+0

如果将SQL语句放入存储过程中,会发生什么情况?当然它会根据需要返回recorset吗?如果不是,那么问题是什么? – 2014-10-28 04:43:38

+0

对不起,也许我应该解释得更好。查询是另一个SP和ETL的一部分。我刚更新了这个问题,希望这个更清晰 – Matt 2014-10-28 04:51:33

回答

1

您的CalcStartCalcEnd计算是仅依赖于行,这是很好的数据。只有CalcLen的计算取决于另一个计算。因此,您可以在线计算CTE中的前两个(即CalcStartCalcEnd),然后使用它们的计算值得到CalcLen,全部在一个镜头中。

请尝试以下操作。我所做的只是将最终的SELECT语句替换为“以某种方式获得SP的结果”,并将开始日期和结束日期计算为列而不是变量。该组合查询是CTE的基础,然后从中选择并现在包括计算值CalcStartCalcEnd。在那一点上,我只是将第三个计算添加为另一列。

;WITH cte AS 
(
    SELECT PrimKey, 
      Name, 
      AppointmentStart, 
      AppointmentEnd, 
      PatArrive, 
      PatDepart, 
      CASE 
       WHEN PatArrive IS NULL THEN AppointmentStart 
       WHEN PatArrive IS NOT NULL THEN 
        CASE 
         WHEN PatArrive BETWEEN Dateadd(MINUTE, -60, AppointmentStart) 
           AND Dateadd(MINUTE, 480, AppointmentStart) 
            THEN PatArrive 
         ELSE AppointmentStart 
        END 
       END AS [CalcStart], 
      CASE 
       WHEN PatDepart IS NULL THEN 
        CASE 
         WHEN AppointmentEnd BETWEEN AppointmentStart AND 
          Dateadd(MINUTE, 480, AppointmentStart) THEN AppointmentEnd 
         ELSE Dateadd(MINUTE, 30, AppointmentStart) 
        END 
       WHEN PatDepart IS NOT NULL THEN 
        CASE 
         WHEN PatDepart BETWEEN AppointmentStart AND 
          Dateadd(MINUTE, 480, AppointmentStart) THEN PatDepart 
         ELSE 
          CASE 
           WHEN AppointmentEnd BETWEEN AppointmentStart 
            AND Dateadd(MINUTE, 480, AppointmentStart) 
            THEN AppointmentEnd 
           ELSE Dateadd(MINUTE, 30, AppointmentStart) 
          END 
         END 
        END AS [CalcEnd] 
    FROM MyTable 
) 
SELECT *, Datediff(MINUTE, [CalcStart], [CalcEnd]) AS [CalcLen] 
FROM cte; 

只是以供将来参考,也有创建内联TVF是发生在4列作为输入参数的选项,并在CTE只是为了让[CalcStart][CalcEnd],并吐出这些值加上计算[CalcLen]

CREATE FUNCTION CalculateDates (@AppointmentStart DATETIME, 
           @AppointmentEnd DATETIME, 
           @PatArrive DATETIME, 
           @PatDepart DATETIME) 
RETURNS TABLE 
AS RETURN 
WITH cte AS 
(
    SELECT 
     CASE 
      WHEN @PatArrive IS NULL THEN @AppointmentStart 
      WHEN @PatArrive IS NOT NULL THEN 
       CASE 
        WHEN @PatArrive BETWEEN DATEADD(MINUTE, -60, @AppointmentStart) 
          AND DATEADD(MINUTE, 480, @AppointmentStart) 
             THEN @PatArrive 
        ELSE @AppointmentStart 
       END 
      END AS [CalcStart], 
     CASE 
      WHEN @PatDepart IS NULL THEN 
       CASE 
        WHEN @AppointmentEnd BETWEEN @AppointmentStart AND 
         DATEADD(MINUTE, 480, @AppointmentStart) THEN @AppointmentEnd 
        ELSE DATEADD(MINUTE, 30, @AppointmentStart) 
       END 
      WHEN @PatDepart IS NOT NULL THEN 
       CASE 
        WHEN @PatDepart BETWEEN @AppointmentStart AND 
         DATEADD(MINUTE, 480, @AppointmentStart) THEN @PatDepart 
        ELSE 
         CASE 
          WHEN @AppointmentEnd BETWEEN @AppointmentStart 
           AND DATEADD(MINUTE, 480, @AppointmentStart) 
           THEN @AppointmentEnd 
          ELSE DATEADD(MINUTE, 30, @AppointmentStart) 
         END 
        END 
       END AS [CalcEnd] 
) 
SELECT [CalcStart], [CalcEnd], DATEDIFF(MINUTE, [CalcStart], [CalcEnd]) AS [CalcLen] 
FROM cte; 
GO 

的功能将被用作如下:

SELECT mt.PrimKey, 
     mt.Name, 
     mt.AppointmentStart, 
     mt.AppointmentEnd, 
     mt.PatArrive, 
     mt.PatDepart, 
     dates.[CalcStart], 
     dates.[CalcEnd], 
     dates.[CalcLen] 
FROM MyTable mt 
CROSS APPLY CalculateDates(mt.AppointmentStart, 
          mt.AppointmentEnd, 
          mt.PatArrive, 
          mt.PatDepart) dates; 

但有没有真正的需要去与功能在第一个例子中所示的直列CTE,如果你不打算使用这些计算在多个地方。同时请记住,内联TVF比多线TVF更有效率(可以执行多个步骤的样式,插入到表变量中,并在最后返回该变量),因此需要重新使用CTE概念功能。

+0

辉煌,谢谢你。我从来没有遇到TVF,我应该开始对它进行一些研究。 – Matt 2014-10-29 00:16:32

1

创建一个表值函数并在select语句中使用它(未测试)。

CREATE FUNCTION Calcdates (@ApptStart DATETIME, 
          @ApptEnd DATETIME, 
          @PatArrive DATETIME, 
          @PatDepart DATETIME) 
RETURNS @Calcdates TABLE (
    CalcStart DATETIME, 
    CalcEnd DATETIME, 
    CalcLen INT) 
AS 
    BEGIN 
     DECLARE @CalcStart DATETIME 
     DECLARE @CalcEnd DATETIME 
     DECLARE @CalcLen INT 

     SET @CalcStart = CASE 
         WHEN @PatArrive IS NULL THEN @ApptStart 
         WHEN @PatArrive IS NOT NULL THEN 
          CASE 
          WHEN @PatArrive BETWEEN Dateadd(MINUTE, -60, @ApptStart) AND Dateadd(MINUTE, 480, @ApptStart) THEN @PatArrive 
          ELSE @ApptStart 
          END 
         END 
     -- CALCUALTED ENDDATETIME 
     SET @CalcEnd = CASE 
         WHEN @PatDepart IS NULL THEN 
         CASE 
          WHEN @ApptEnd BETWEEN @ApptStart AND Dateadd(MINUTE, 480, @ApptStart) THEN @ApptEnd 
          ELSE Dateadd(MINUTE, 30, @ApptStart) 
         END 
         WHEN @PatDepart IS NOT NULL THEN 
         CASE 
          WHEN @PatDepart BETWEEN @ApptStart AND Dateadd(MINUTE, 480, @ApptStart) THEN @PatDepart 
          ELSE 
          CASE 
           WHEN @ApptEnd BETWEEN @ApptStart AND Dateadd(MINUTE, 480, @ApptStart) THEN @ApptEnd 
           ELSE Dateadd(MINUTE, 30, @ApptStart) 
          END 
         END 
        END 
     -- CALCULATED LENGTH 
     SET @CalcLen = Datediff(MINUTE, @CalcStart, @CalcEnd) 

     INSERT INTO @Calcdates 
     VALUES  (@CalcStart,@CalcEnd,@CalcLen) 

     RETURN; 
    END; 

SELECT PrimKey, 
     Name, 
     AppointmentStart, 
     AppointmentEnd, 
     PatArrive, 
     PatDepart, 
     T.CalcStart, 
     T.CalcEnd, 
     T.CalcLen 
FROM MyTable 
     CROSS apply Calcdates(AppointmentStart, AppointmentEnd, PatArrive, PatDepart) as T