对select RESULT中的每一行执行INSERT

时间:2013-06-29 18:54:04

标签: sql-server tsql

首先,问题的一般描述:我正在运行一个更新表中总数的定期过程。问题是,每次执行过程都可能需要多次更新,每次执行都取决于之前的结果。

我的问题是,可以在单个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循环,我猜...)?

1 个答案:

答案 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 );