2016-06-08 16 views
-1

ich diese Tabelle in MS SQL haben, wie dieses IchBegrenzung der Summe einer Spalte mit einem Wert in einer anderen Spalte

ID   DATE    LIMIT  VALUE 
    1  2016-01-01 00:00:00  10  5 
    1  2016-02-01 00:00:00  10  3 
    1  2016-03-01 00:00:00  10  1 
    1  2016-04-01 00:00:00  10  3 
    2  2016-01-01 00:00:00  15  16 
    2  2016-02-01 00:00:00  15  5 
    3  2016-01-01 00:00:00  8  1 
    3  2016-02-01 00:00:00  8  2  
    3  2016-03-01 00:00:00  8  2 
    3  2016-04-01 00:00:00  8  0 
    3  2016-05-01 00:00:00  8  1 

sieht eine SELECT-Anweisung erstellen möchten, die die Summe von VALUE durch das verkappte wird GRENZE. Wie unten

gezeigt
ID   DATE    LIMIT  VALUE 
    1  2016-01-01 00:00:00  10  5 
    1  2016-02-01 00:00:00  10  3 
    1  2016-03-01 00:00:00  10  1 
    1  2016-04-01 00:00:00  10  1 
    2  2016-01-01 00:00:00  15  15 
    2  2016-02-01 00:00:00  15  0 
    3  2016-01-01 00:00:00  8  1 
    3  2016-02-01 00:00:00  8  2  
    3  2016-03-01 00:00:00  8  2 
    3  2016-04-01 00:00:00  8  0 
    3  2016-05-01 00:00:00  8  1 

Wie Sie den Wert in der Zeile 4,5, sehen können, und 6 geändert wird, so dass der laufende Gesamtwert von ID, Datum und LIMIT LIMIT nicht überschreiten wird. (Reihe 6, die 0 in VALUE hat, können gelöscht werden.)

Um klar zu sein, LIMIT auf die laufende Summe gilt, basierend auf Bestellung von DATE (dank Damien_the_unbeliever machen es klarer)

Jede Hilfe ist sehr viel geschätzt. Vielen Dank!

+0

so, wenn Kappungsgrenze überschreitet Sie versuchen, die von 1 bis Standardwert zu setzen? – TheGameiswar

+1

könnte es negative Zahlen oder Nullen in der Spalte Wert geben? – dean

+1

Also, um klar zu sein, gilt "LIMIT" für die * laufende Summe *, basierend auf * Bestellung * von 'DATE' (anstatt' GROUP's, wie Ihre Frage sagt). –

Antwort

2

Daraus ergibt sich die Ergebnismenge gewünscht wird, und ist hoffentlich recht einfach über zu lesen und Grund:

declare @t table (ID int not null,[DATE] datetime not null, LIMIT int not null, 
        VALUE int not null) 
insert into @t(ID,[DATE],LIMIT,VALUE) values 
(1,'2016-01-01T00:00:00',10,5), 
(1,'2016-02-01T00:00:00',10,3), 
(1,'2016-03-01T00:00:00',10,1), 
(1,'2016-04-01T00:00:00',10,3), 
(2,'2016-01-01T00:00:00',15,16), 
(2,'2016-02-01T00:00:00',15,5), 
(3,'2016-01-01T00:00:00', 8,1), 
(3,'2016-02-01T00:00:00', 8,2), 
(3,'2016-03-01T00:00:00', 8,2), 
(3,'2016-04-01T00:00:00', 8,0), 
(3,'2016-05-01T00:00:00', 8,1) 

select ID,[DATE],LIMIT, 
    CASE 
     WHEN v2 > LIMIT THEN 0 
     WHEN COALESCE(v2,0) + VALUE > LIMIT THEN LIMIT - COALESCE(v2,0) 
     ELSE VALUE 
    END as VALUE 
from 
    @t t 
     cross apply 
    (select SUM(VALUE) from @t v where v.ID = t.ID and v.[DATE] < t.[DATE]) v(v2) 

Ergebnisse:

ID   DATE     LIMIT  VALUE 
----------- ----------------------- ----------- ----------- 
1   2016-01-01 00:00:00.000 10   5 
1   2016-02-01 00:00:00.000 10   3 
1   2016-03-01 00:00:00.000 10   1 
1   2016-04-01 00:00:00.000 10   1 
2   2016-01-01 00:00:00.000 15   15 
2   2016-02-01 00:00:00.000 15   0 
3   2016-01-01 00:00:00.000 8   1 
3   2016-02-01 00:00:00.000 8   2 
3   2016-03-01 00:00:00.000 8   2 
3   2016-04-01 00:00:00.000 8   0 
3   2016-05-01 00:00:00.000 8   1 

Wir verwenden nur einen CROSS APPLY hier Finden Sie heraus, was der Gesamtwert für alle vorherigen Zeilen ist (basierend auf DATE) und verwenden Sie einen kurzen Ausdruck CASE, um zu entscheiden, in welcher der drei Situationen jede Zeile sein könnte - wir haben entweder exceede d das Limit schon, wir sind die Zeile, die das Limit überschreitet, oder wir sind weit unter dem Limit.


Beachten Sie auch, wie ich Ihre Beispieldaten in etwas verwandelt haben, die so viel/etwas weniger Platz als die Probe in Ihrer Frage aufgreift, sondern hat auch den massiven Vorteil, dass es runnable Code ist zu Generieren Sie die Beispieldaten

Die ursprüngliche Version dieser Antwort schlug fehl, wenn die erste Zeile eines Satzes den Grenzwert (wie für die Frage ID 2 Zeilen) überschritten wurde. Es wurde seither korrigiert, um COALESCE für diesen Fall zu verwenden.

0

Was Sie wahrscheinlich brauchen

LEAST(YourTable.Limit, SUM(YourTable.Value)) as Value 

und eine Gruppe mit dem ID und Datum zu tun, aber nicht genug, um Ihre Rohdaten komplette SQL zu zeigen.

0

Art

WITH cte AS (
    SELECT *, rt=SUM(Value) OVER(PARTITION BY id ORDER BY [DATE]) 
    FROM YourTable 
) 
SELECT ID,DATE,LIMIT 
     ,VAL = CASE WHEN rt - value > LIMIT THEN 0 
      ELSE CASE WHEN rt > LIMIT THEN rt - LIMIT ELSE value END END 
FROM cte 
Verwandte Themen