sql >> Database teknologi >  >> RDS >> Sqlserver

Gruppér række efter sum af specifik kolonne lig med specifik værdi

Med en hjælpetabel, der definerer "Forfalden" grænser pålagt over kildetabellen med den løbende total beregnet, kan en skæring af hvert løbende samlede beløb med "Forfalden" grænserne beregnes:

With Receipt As ( --< Sample source table
    Select * From (Values
        ('R1', 100),
        ('R2', 100),
        ('R3',  70),
        ('R4',  50),
        ('R5', 200)
    ) V (ReceiptNo, Amount)
), ReceiptWithTotal As ( --< Source table with Running Totals calculated
    Select *,
        SUM(Amount) Over (Order By ReceiptNo Rows Unbounded Preceding) - Amount As RunningTotalBefore,
        SUM(Amount) Over (Order By ReceiptNo Rows Unbounded Preceding) As RunningTotalAfter
    From Receipt
), Due As ( --< Helper table to define intervals (can be generated dynamically to cover any Total)
    Select * From (Values
        ('D1',   0, 100),
        ('D2', 100, 200),
        ('D3', 200, 300),
        ('D4', 300, 400),
        ('D5', 400, 500),
        ('D6', 500, 600)
    ) V (DueNo, AmountLow, AmountHigh)
)
Select DueNo, ReceiptNo,
    IIF(AmountHigh < RunningTotalAfter, AmountHigh, RunningTotalAfter) -
    IIF(AmountLow > RunningTotalBefore, AmountLow, RunningTotalBefore) As Amount
From Due
Inner Join ReceiptWithTotal On NOT (RunningTotalAfter <= AmountLow OR RunningTotalBefore >= AmountHigh)

Bemærk venligst:SUM(...) Over (Order By ... Rows Unbounded Preceding) og IIF(...) er kun tilgængelige på SQL Server 2012+. Det samme kan gøres på SQL Server 2008 gennem underforespørgsel, men meget mindre effektivt:

With Receipt As ( --< Sample source table
    Select * From (Values
        ('R1', 100),
        ('R2', 100),
        ('R3',  70),
        ('R4',  50),
        ('R5', 200)
    ) V (ReceiptNo, Amount)
), ReceiptWithTotal As ( --< Source table with Running Totals calculated
    Select *, RunningTotalAfter - Amount As RunningTotalBefore
    From (
        Select *,
            (Select SUM(Amount) From Receipt B Where B.ReceiptNo <= A.ReceiptNo) As RunningTotalAfter
        From Receipt A
    ) A
), Due As ( --< Helper table to define intervals (can be generated dynamically to cover any Total)
    Select * From (Values
        ('D1',   0, 100),
        ('D2', 100, 200),
        ('D3', 200, 300),
        ('D4', 300, 400),
        ('D5', 400, 500),
        ('D6', 500, 600)
    ) V (DueNo, AmountLow, AmountHigh)
)
Select DueNo, ReceiptNo,
    CASE WHEN AmountHigh < RunningTotalAfter THEN AmountHigh ELSE RunningTotalAfter END -
    CASE WHEN AmountLow > RunningTotalBefore THEN AmountLow ELSE RunningTotalBefore END As Amount
From Due
Inner Join ReceiptWithTotal On NOT (RunningTotalAfter <= AmountLow OR RunningTotalBefore >= AmountHigh)



  1. Sådan udtrækkes en understreng fra en streng i PostgreSQL/MySQL

  2. SQL:Begrænsning af CASE (antal af NÅR, SÅ betingelser)

  3. Sådan bruger du Database Documenter i Access

  4. Problemer med en PostgreSQL-upsert-forespørgsel