我有一个包含四个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,并为每条记录提供计算值。
有人知道怎么做吗?或者我是以错误的方式去做的?
答案 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)
CalcStart
和CalcEnd
的计算仅取决于行中的数据,这很好。只有CalcLen
的计算依赖于另一个计算。因此,您可以在CTE中对前两个(即CalcStart
和CalcEnd
)的计算进行内联,然后使用它们的计算值来获取CalcLen
,一次性完成。
尝试以下方法。我所做的就是拿出你的最终SELECT语句并替换"不知怎的,这里有SP的结果"将开始日期和结束日期计算为列而不是变量。该组合查询是CTE的基础,然后从中选择,现在包括CalcStart
和CalcEnd
的计算值。那时我刚刚将第三个计算添加为另一列。
;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概念功能。