2013-06-29 3 views
2

먼저, 문제에 대한 일반적인 설명 : 테이블의 총 숫자를 업데이트하는 정기 프로세스를 실행하고 있습니다. 문제는 프로세스를 실행할 때마다 여러 업데이트가 필요할 수 있으며 각 실행은 이전 결과에 따라 달라질 수 있다는 것입니다.select 결과의 각 행에 대해 INSERT 수행

제 질문은 단일 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 APPLYTVF_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 

은 무엇 최고 (즉, 루프없는 것 같아요 ...) 이후 행에 대한 쿼리 내에서 이전 행을 취할?

+0

SQL 버전? 각 레코드에 증가 세션 수 또는 각 항목의 합계를 저장하려고합니까? – Volvox

+0

@Volvox : 답장 (그리고 내 의견과 편집에 뒤따른 것)에 무슨 일이 일어 났습니까 ?? – ury

답변

0

SQL-2005 이상을 사용하는 경우 한 번에 몇 개의 CTE를 사용하여 수행 할 수 있습니다. SQL-2000을 사용하는 경우 인라인 테이블 반환 함수를 사용할 수 있습니다.

저는 개인적으로 CTE 방식이 더 좋아서 CTE 구문에 대한 코드의 설계도 번역본을 포함하고 있습니다. (내가 시험해보기 위해 시험 준비를하지 않았다는 것을 염두에 두라.) 테이블 CustomerMinuteSessions 데이터베이스 성장하면 질문을 넘어 조금가는

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 

, 나는 인덱스는 인덱스-탐색 얻기의 기회를 개선하고자 추가 할 십자가와 쿼리가 데이터베이스에 큰 손상을 만들 수 적용하는 것이 생각 :

CREATE INDEX IX_CustomerMinuteSessions_CustomerId 
    ON CustomerMinuteSessions (CustomerId, [time] DESC, PreviousNumberOfSessions, Opened, Closed); 
+0

저는 SQL Server 2012를 사용하고 있습니다. 우수한 기사 [here] (http://www.sqlperformance.com/2012/07/t-sql-queries/running-totals)를 발견했습니다. SQL 2012 Windows 또는 커서. Windows의 문제점은 SQL Server의 'Sum'과 유사하지 않은 함수에 대한 솔루션을 파악할 수 없다는 것입니다. – ury

+0

실제로, 그것은 훌륭한 기사입니다! 어쩌면 내가 잘못 이해 한 것 같지만, 이것이 당신의 경우는 아니라고 생각합니다. 기사에서 정의한 방식으로 누적되고 있다는 것을 알지 못했습니다. 변수'time> @ time'을 기반으로 최신 행을 읽은 후 'WHERE CustomerId = @ customerId' 함수를 사용하여 고객과 연결합니다. 따라서 여전히 나의 접근법이 타당하다고 믿습니다. –

관련 문제