2014-10-28 48 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