Donnerstag, 4. August 2016

Berechnete Datensätze mit SQL INSERT INTO () SELECT ergänzen

Ein Kunde setzt seit 2011 eine zentrale Verwaltung und Erfassung von Zählern ein. Die Ablesung erfolgt monatlich mit Hilfe eines mobilen Gerätes. Die abgelesenen Stände werden anschließend per LAN in eine Oracle Datenbank synchronisiert.
Dabei werden gleichzeitig neue Stammdaten (Zähler) auf das mobile Gerät übernommen.

Die Auswertung der Daten erfolgt über ein zentrales Berichtssystem mit JasperReports unabhängig von der Zählerverwaltung.

In der Auswertung werden monatliche Verbrauche dargestellt. Die Ermittlung erfolgt ganz einfach durch Subtraktion eines Zählerstands mit dem Stand des Vormonats.
Dies funktioniert natürlich nur, wenn für alle Monate lückenlos Stände erfasst wurden.

Aufgrund von Urlaub wurde nun für den Monat Juni 2016 kein Stand abgelesen. Damit waren die Auswertungen unvollständig, da ohne den Stand für Juni keine Verbrauche für Mai und Juni ermittelt werden können.
Das Problem ist erst Anfang August aufgefallen und nun musste eine Lösung gefunden werden.

Lösung:

  • Die Stände für Juli werden regulär erfasst.
  • Die Stände für Juni werden berechnet und nachgetragen. Dabei wird die Mitte zwischen Mai und Juli angenommen.


Im System sind ca. 120 Zähler abzulesen. Eine manuelle Berechnung und Nacherfassung der Stände für Juni hätte Arbeit und vor Allem Fehlerpotenzial bedeutet.

Ich habe daher eine SQL Abfrage erstellt, die die fehlenden Stände nachträgt. Dafür eignet sich die INSERT INTO (...) SELECT ... Syntax.
Mit dieser Syntax werden Datensätze eingefügt, die aus einer SELECT Abfrage gewonnen werden.


Vorabprüfung und Backup

Man muss bei solchen Aktionen natürlich aufpassen, da man mit fehlerhaftem SQL ganz fix den Datenbestand zerstören kann. Man startet also am Besten mit einer Datensicherung.

Danach habe ich geprüft, ob für Mai und Juli gleich viele Stände abgelesen wurden.

Anzahl Stände für Mai

select count(*) from zaehler_stand zs
  where zs.PERIODE_BEGINN = TO_DATE('1.5.2016')

Ergebnis: 122


Anzahl Stände für Juli

select count(*) from zaehler_stand zs
  where zs.PERIODE_BEGINN = TO_DATE('1.7.2016')

Ergebnis: 123

Die Abweichung resultiert aus einem neuen Zähler, der erst im Juni in Betrieb gegangen ist. Die Basis für die INSERT INTO Abfrage bilden also alle Zähler für die im Mai ein Stand erfasst wurde.


Hier nun die entsprechende Abfrage:


insert into zaehler_stand (periode_beginn, periode_ende,
     zaehler_nummer, datum_ablesung, version, zaehler_stand)

select 

TO_DATE('1.6.2016'),
TO_DATE('30.6.2016'),
zaehler.zaehler_nummer,
TO_DATE('4.8.2016'),
1,
(
   (select zaehler_stand from zaehler_stand zs where 
       zs.PERIODE_BEGINN = TO_DATE('1.7.2016')
       and zs.zaehler_nummer = zaehler.zaehler_nummer) + 
   (select zaehler_stand from zaehler_stand zs where
       zs.PERIODE_BEGINN = TO_DATE('1.5.2016') 
       and zs.zaehler_nummer = zaehler.zaehler_nummer)
) / 2

from zaehler

where zaehler_nummer in 
 (select zaehler_nummer from zaehler_stand where
     PERIODE_BEGINN = TO_DATE('1.5.2016'))


Die Datumsangaben entsprechend den Werten für Juni 2016. Das Feld version wird mit 1 belegt. Die Zählernummer wird aus dem aktuellen Datensatz der Tabelle zaehler übernommen.

Über 2 Subqueries werden die Stände des aktuellen Zählers für Mai und Juli 2016 ermittelt. Die Stände werden addiert und durch 2 dividiert. Dies ergibt den Mittelwert für Juni.

Im WHERE Teil der Hauptabfrage werden per Subquery die Zähler eingeschränkt, so dass nur die Zähler verarbeitet werden für die im Mai 2016 ein Stand abgelesen wurde.


Keine Kommentare:

Kommentar veröffentlichen