如何在sql查询中从存储过程返回多个值

时间:2014-10-28 04:42:13

标签: sql sql-server tsql datetime stored-procedures

我有一个包含四个datetime列的约会表:

AppointmentStart
AppointmentEnd
Arrival
Departure

现在数据一团糟,有时到来和/或离开是空的,将来,过去,整个节目。 AppointmentEnd甚至被发现在AppointmentStart之前。

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

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,并为每条记录提供计算值。

有人知道怎么做吗?或者我是以错误的方式去做的?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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概念功能。