Freitag, 4. Juni 2010

Test1

Dieses Beispiel soll die Problemstellung erkennen lassen. Es zeigt eine Tabelle mit fortschreitenden Verbrauch und Betriebsstundenzähler.
WerteTabelle

BetriebsstundenVerbrauch
11,8
24,6
36,8
47,7
59,0
612,3
714,8
815,9
Unser Interesse gilt der Berechnung des Verbrauchs pro Stunde. Dazu muss man nur jeweils die Differenz aller Verbrauchswerte berechnen:
BetriebsstundenVerbrauchMinusVerbrauch Zeile vorheristVerbrauch pro Stunde
11,8
-
0,0
=
1,8
24,6
-
1,8
=
2,8
36,8
-
4,6
=
2,2
57,7
-
6,8
=
0,9
69,0
-
7,7
=
1,3
712,3
-
9,0
=
3,3
814,8
-
12,3
=
2,5
915,9
-
14,8
=
1,1

Wie mach man das mit SQL?  
 

Mein erster "Reflex" einer Lösung ging über ein CURSOR in einer Stored Procedure. Dies klappt natürlich auch. Besinnt man sich aber darauf, dass SQL eine Mengenabfragesprache ist, so kann man eine elegantere Lösung finden. Wir haben zwei Mengen. Unserer Ausgangstabelle und die Menge der Ausgangstabelle um eine Zeile verschoben. Wir JOINen beide Mengen und subtrahieren die Verbrauchswerte

Wie aber nun einen JOIN auf die Zeile vorher machen? 


Seit SQL 2005 gibt es die TSQL Funktion ROW_NUMBER. Sie gibt als Integer die Nummer der Zeile zurück. Wir können den erforderlichen JOIN auf die Zeile vorher durchführen, indem in der zweiten Menge die ROW_Number minus 1 zurückgeben: 



Menge von Spalte Verbrauch
mit ROW_Number

VerbrauchROW_NUMBER
1,81
4,62
6,83
7,74
9,05
12,36
14,87
15,98
Menge von Spalte Verbrauch
mit ROW_Number minus 1

ROW_NUMBER - 1Verbrauch
1-1 = 01,8
2 -1 = 14,6
3 -1 = 26,8
4 -1 = 37,7
5 -1 = 49,0
6 -1 = 512,3
7 -1 = 614,8
8 -1 = 715,9
JOIN von ROW_NUMBER auf ROW_NUMBER minus 1

VerbrauchROW_NUMBERROW_NUMBER 0 - 1Verbrauch
01,8
1,8114,6
4,6226,8
6,8337,7
7,7449,0
9,05512,3
12,36614,8
14,87715,9
15,98

Mit einer CTE können wir nun das Ergebnis gleich in einem Rutsch ausgeben:


WITH WerteTabelle(Betriebsstunden, Verbrauch)
AS
(
    SELECT Betriebsstunden = 1, Verbrauch = 1.8 UNION
    SELECT Betriebsstunden = 2, Verbrauch = 4.6 UNION
    SELECT Betriebsstunden = 3, Verbrauch = 6.8 UNION
    SELECT Betriebsstunden = 4, Verbrauch = 7.7 UNION
    SELECT Betriebsstunden = 5, Verbrauch = 9.0 UNION
    SELECT Betriebsstunden = 6, Verbrauch = 12.3 UNION
    SELECT Betriebsstunden = 7, Verbrauch = 14.8 UNION
    SELECT Betriebsstunden = 8, Verbrauch = 15.9
    
)
,Menge1(Nr, Betriebsstunden, Verbrauch)
AS
(
    SELECT
        -- Zeilennummer
        ROW_NUMBER() OVER (ORDER BY Betriebsstunden) AS 'Nr',
        Betriebsstunden,
        Verbrauch
    FROM WerteTabelle
)
,Menge2(NrMinusEins, Betriebsstunden, Verbrauch)
AS
(
    SELECT
        -- Zeilennummer minus 1
        (ROW_NUMBER() OVER (ORDER BY Betriebsstunden) - 1) AS 'NrMinusEins',
        Betriebsstunden,
        Verbrauch
    FROM WerteTabelle
)


SELECT
    Menge1.Betriebsstunden,
    Menge1.Verbrauch,
    Menge2.Verbrauch AS 'Verbrauch Zeile Vorher',
    Menge2.Verbrauch - Menge1.Verbrauch AS 'Verbrauch pro Stunde'
FROM
    Menge1
-- JOIN Zeilennummer auf Zeilennummer minus 1
INNER JOIN Menge2 ON Menge1.Nr = Menge2.NrMinusEins

 

Freitag, 21. Mai 2010