SQL Server Loop через записи - PullRequest
1 голос
/ 08 июля 2011

Я искал лучший способ переписать эту текущую VBA / MS Access Sub для работы в хранимой процедуре в SQL Server 2005. Мы не должны использовать CURSORS для элементов, если мы не сможем полностью объяснить причиныпочему мы не можем сделать это по-другому.

Текущий код:

Public Sub updcsh()

Dim tranamt
Dim Acct
Dim acct2
Dim Csh
Dim recSet As Recordset

    DAO.DBEngine.SetOption dbMaxLocksPerFile, 100000

    Set recSet = CurrentDb.OpenRecordset("FndVios")
    recSet.MoveFirst


    Do Until recSet.EOF
        Acct = recSet![ID]
        tranamt = recSet![TAM]

        If Acct <> acct2 Then
            Csh = recSet![Due]
        End If

        Csh = Csh+ tranamt
        acct2 = Acct

        recSet.Edit
            recSet![Due] = Csh
        recSet.Update

        recSet.MoveNext
    Loop
End Sub

Ниже открывается набор записей:

SELECT ID, EXEC_TM, Due, TAM
FROM FRT
ORDER BY ID, EXEC_DT, EXEC_TM, D_C_CD, SEQ_NBR, TAM DESC

Я искал в SO и нашел this ,Я посмотрел на курсоры и другие методы, как написать это для хранимого процесса, и я не могу найти правильный способ переписать это.

Может кто-нибудь предложить какие-либо предложения?Должен ли я использовать временную таблицу?Я не делал этого раньше, и я озадачен тем, как действовать.

РЕДАКТИРОВАТЬ:

Sample Data
Original:

ID         EXEC_TM    Due        TAM
12345678   12343811   $9250.81   $-6561.91
12345678   12343822   $9250.81   $-4374.63
12345678   15581917   $9250.81   $-4762.76

Final Result:

ID         EXEC_TM    Due         TAM
12345678   12343811   $2688.87    $-6561.91
12345678   12343822   $-1685.76   $-4374.63
12345678   15581917   $-6448.52   $-4762.76

Ответы [ 2 ]

7 голосов
/ 08 июля 2011

Ответ Тома - лучший с точки зрения редизайна процесса.Код ниже является близким воссозданием вашей текущей логики в форме CURSOR.

Я ни в коем случае не одобряю этот метод , но это то, что вы просили.Вам может потребоваться исправить типы данных и т. Д., Чтобы он работал правильно.

DECLARE @ID int,
        @Exec_TM int,
        @Due money,
        @TAM money,
        @ID2 int = 0,
        @Cash money


DECLARE RecSet CURSOR FOR

SELECT ID, EXEC_TM, Due, TAM
FROM FRT
ORDER BY ID, EXEC_DT, EXEC_TM, D_C_CD, SEQ_NBR, TAM DESC

OPEN RecSet
FETCH NEXT FROM RecSet INTO @ID, @Exec_TM, @Due, @TAM

WHILE (@@FETCH_STATUS = 0)  
        BEGIN  

            IF @ID <> @ID2 SET @Cash = @Due

            SET @Cash = @Cash + @TAM

            SET @ID2 = @ID

            UPDATE FRT
            SET Due = @Cash
            WHERE ID = @ID
            AND EXEC_TM = @Exec_TM
            AND Due = @Due
            AND TAM = @TAM  

            FETCH NEXT FROM RecSet INTO @ID, @Exec_TM, @Due, @TAM

        END


CLOSE RecSet
DEALLOCATE RecSet
3 голосов
/ 08 июля 2011

Во-первых, сохранение суммы «в срок» - ужасная идея с точки зрения проектирования базы данных (и, вероятно, с точки зрения бухгалтерского учета).

Во-вторых, с вашей логикой, если в первом ряду для учетной записи есть сумма транзакции для учетной записи, то каждый раз, когда вы запускаете этот процесс, она будет все больше и больше сбрасывать вашу причитающуюся сумму, пока вы не начнете задолжать клиентам.

Вот базовый подход, основанный на наборе, хотя для расчета промежуточных итогов:

SELECT
    L1.account_id,
    L1.transaction_date,
    L1.amt,
    SUM(L2.amt)
FROM
    Ledger L1
INNER JOIN Ledger L2 ON
    L2.account_id = L1.account_id AND
    L2.transaction_date <= L1.transaction_date
GROUP BY
    L1.account_id,
    L1.transaction_date,
    L1.amt

Поскольку у вас есть этот столбец «должный» отдельно, это вызовет проблемы здесь, потому что похоже, что вы рассчитываете это только для первой записи. Вы можете учесть это в приведенном выше запросе, но это будет включать в себя подзапрос или дополнительные объединения.

...