首先,问题的一般描述:我正在运行一个更新表中总数的定期过程。问题是,每次执行过程都可能需要多次更新,每次执行都取决于之前的结果。
我的问题是,可以在单个SQL Server SP中完成吗?
我的代码(我将其改为简单的样本):
INSERT INTO CustomerMinuteSessions(time, customer, sessions, bytes, previousTotalSessions)
SELECT MS.time,
MS.customer,
MS.totalSessions,
MS.totalBytes,
CTS.previousTotalSessions
FROM (SELECT time, customer, SUM(sessions) as totalSessions, SUM(bytes) AS totalBytes
FROM MinuteSessions
WHERE time > @time
GROUP BY time, x) MS
CROSS APPLY TVF_GetPreviousCustomerTotalSessions(MS.customer) CTS
ORDER BY time
previousTotalSessions
列取决于UpdatedTable
中的其他行,其值由CROSS APPLY
TVF_GetPreviousCustomerTotalSessions
检索,但如果我按原样执行SP,则全部行使用函数检索的值,而不执行执行SP期间添加的行。
为了完整起见,这里是TVF_GetPreviousCustomerTotalSessions
:
FUNCTION [dbo].[TVF_GetCustomerCurrentSessions]
(
@customerId int
)
RETURNS @result TABLE (PreviousNumberOfSessions int)
AS
BEGIN
INSERT INTO @result
SELECT TOP 1 (PreviousNumberOfSessions + Opened - Closed) AS PreviousNumberOfSessions
FROM CustomerMinuteSessions
WHERE CustomerId = @customerId
ORDER BY time DESC
IF @@rowcount = 0
INSERT INTO @result(PreviousNumberOfSessions) VALUES(0)
RETURN
END
对于后续行,查询中的前一行是最好的(即没有for循环,我猜...)?
答案 0 :(得分:0)
如果您使用的是SQL-2005及更高版本,则可以一次性使用少量CTE。如果使用SQL-2000,则可以使用内联表值函数。
我个人更喜欢CTE方法,因此我将代码的原理图转换为CTE语法。 (请记住,我没有准备一套测试装置来检查它。)
WITH LastSessionByCustomer AS
(
SELECT CustomerID, MAX(Time)
FROM CustomerMinuteSessions
GROUP BY CustomerID
)
, GetPreviousCustomerTotalSessions AS
(
SELECT LastSession.CustomerID, LastSession.PreviousNumberOfSessions + LastSession.Opened - LastSession.Closed AS PreviousNumberOfSessions
FROM CustomerMinuteSessions LastSession
INNER JOIN LastSessionByCustomer ON LastSessionByCustomer.CustomerID = LastSession.CustomerID
)
, MS AS
(
SELECT time, customer, SUM(sessions) as totalSessions, SUM(bytes) AS totalBytes
FROM MinuteSessions
WHERE time > @time
GROUP BY time, x
)
INSERT INTO CustomerMinuteSessions(time, customer, sessions, bytes, previousTotalSessions)
SELECT MS.time,
MS.customer,
MS.totalSessions,
MS.totalBytes,
ISNULL(GetPreviousCustomerTotalSessions.previousTotalSessions, 0)
FROM MS
RIGHT JOIN GetPreviousCustomerTotalSessions ON MS.Customer = GetPreviousCustomerTotalSessions.CustomerID
稍微超出您的问题,我认为一旦表CustomerMinuteSessions数据库增长,您的带有交叉应用的查询可能会对数据库造成很大的损害 我会添加一个索引,以提高你获得Index-Seek的机会:
CREATE INDEX IX_CustomerMinuteSessions_CustomerId
ON CustomerMinuteSessions (CustomerId, [time] DESC, PreviousNumberOfSessions, Opened, Closed );