Konzept und Umsetzung einer automatischen Messwertarchivierung

Werbung
GhK
Universität–G esam tho c hsc hule Kassel
Z UB - Z entrum fü rUm w eltg erec htes B auen
Diplo m arbeitII
Ko nz eptund Um setz u ng
einerauto m atisc hen
M essw ertarc hivierung m it
O RAC LE
UniversitätG esam tho c hsc hule Kassel
F ac hg ebiete Bauphy sik / TG A, G o ttsc halkstr.28 , 34109 Kassel
Verfasser
Ax elSeibel
12.02.2001
1
Universität Gesamthochschule Kassel
Diplomarbeit II
Konzept und Umsetzung einer automatischen
Messwertarchivierung mit ORACLE
von
Dipl.-Ing. Axel Seibel
Mat.-Nr.: 668206
Betreuer:
Univ.-Prof. Dr.-Ing. Jürgen Schmid (Fachbereich 16 Elektrotechnik)
Univ.-Prof. Dr.-Ing. Gerhard Hausladen (Fachbereich 12 Architektur)
Dipl.-Ing. Jens Oppermann (Fachbereich 12 Architektur)
INHALT
1
EINLEITUNG .................................................................................. 5
1.1 Allgemein .............................................................................................. 5
1.2 Abweichung zur Aufgabenstellung und weitere Informationen ........... 5
2
ABKÜRZUNGEN............................................................................. 6
2.1 Allgemeine............................................................................................. 6
2.2 Abkürzungen für die Datenbanktabellen .............................................. 6
3
KONZEPT DER DATENBANK FÜR DAS ZENTRUM FÜR
UMWELTGERECHTES BAUEN (ZUB)............................................... 7
3.1 Grundlegendes ...................................................................................... 7
3.1.1 Datenerfassung der Gebäudeleittechnik und der Klimadaten...................... 7
3.1.2 Informationsschwerpunkte der ZUB Leittechnik ......................................... 8
3.1.3 Redundanzen der Informationsschwerpunkte .............................................. 9
3.1.4 Bereitstellung der Messdaten, Schnittstelle zur Datenbank ........................10
3.1.5 Nutzen der Redundanzen der Messpunkte ..................................................10
3.1.6 Bezeichnungen für die Spaltennamen wählen.............................................11
3.1.7 Anforderungen an die Leittechnik und die ZUB Datenbank........................12
3.1.8 Begriffe im weiteren Verlauf ......................................................................13
3.2 Aufbau und Übersicht......................................................................... 14
3.2.1 Aufbau der benötigten Datentabellen.........................................................14
3.2.2 Aufbau der benötigten Fehlertabellen........................................................15
3.2.3 Struktur der Datenbank .............................................................................16
3.2.4 Die Umgebungstabellen ZUORDNUNG und ANHANG .............................18
3.2.5 Weitere wichtige Umgebungstabellen ........................................................20
3.2.5.1 Die Zeitreferenztabelle ZEITTAB............................................................. 20
3.2.5.2 Tabellen FEHLER_CODE, FEHL_AUTO_ANZEIGE_TAB und
FEHL_TAB............................................................................................................. 21
3.3 Datenfluss und Verarbeitung .............................................................. 24
3.3.1 Automatisierter täglicher Ablauf................................................................26
3.3.1.1
Ein Beispiel: Täglicher Datenfluss ............................................................ 26
2
3.3.1.2
3.3.1.3
Verbessern ungenauer Datumseinträge aus ZUB_DATEN_TMP_TAB ..... 28
Automatische Fehlerkontrolle ................................................................... 30
3.3.2 Manueller Ablauf mit Blick auf die Tabelle FEHL_TAB ............................31
4
REALISIERUNG ........................................................................... 34
4.1 Anlegen der Datenbank....................................................................... 34
4.1.1 Verzeichnisse.............................................................................................34
4.1.2 Vorbereitung .............................................................................................35
4.1.3 Die Datenbank neu anlegen (Ablaufstrg_DB_neu_anlegen.sql).................35
4.2 Datenbanktabellen anlegen/ändern
(Ablaufstrg_DB_Tabellen_anlegen.sql) ...................................................... 38
4.2.1 Übersicht...................................................................................................38
4.2.2 Zuordnung prüfen (Funktion_Zuordnung_pruefen.sql) ..............................39
4.2.3 Anlegen / Ändern der Datentabellen (DB_Tabellen_anlegen.sql) ..............42
4.3 Ändern von ZUORDNUNG ................................................................ 44
4.3.1 Hinzufügen von Zeilen ...............................................................................44
4.3.2 Löschen von Zeilen....................................................................................45
4.3.3 Ändern von Zeilen .....................................................................................46
4.4 Ausführen der Datenbank................................................................... 46
4.4.1 Tägliche Ablaufsteuerung (Ablaufstrg_taeglich.sql) ..................................47
4.4.2 Füllen der Datentabellen zur Auswertung (Ablaufstrg_manuell.sql) ..........49
5
BEARBEITUNG DER DB UNTER ORACLE FORMS.............. 52
5.1 Fehlertabellen bearbeiten ................................................................... 52
5.2 ZUORDNUNG bearbeiten .................................................................. 56
5.3 Messbereich ändern ............................................................................ 59
5.4 Fehlertabelle bearbeiten...................................................................... 60
5.5 Die Symbolleiste .................................................................................. 62
6
ZUSAMMENFASSUNG UND AUSBLICK ................................. 64
6.1 Zusammenfassung .............................................................................. 64
6.2 Ausblick............................................................................................... 66
3
7
LITERATUR .................................................................................. 68
8
ABBILDUNGSVERZEICHNIS .................................................... 69
9
ANHANG ........................................................................................ 70
9.1 PL/SQL Skripte ................................................................................... 70
9.2 CD-ROM ............................................................................................139
9.2.1 Diese Ausarbeitung .................................................................................139
9.2.2 PL/SQL Skripte, Eingabemaske unter ORACLE Forms............................139
4
Einleitung
1 Einleitung
1.1 Allgemein
Diese Arbeit befasst sich mit der Archivierung und Aufbereitung von Messdaten unter
dem relationalen Datenbankprogramm Oracle. Die Messdaten werden im „Zentrum für
umweltbewusstes Bauen“ (ZUB) erfasst und stehen der Datenbank zur Verfügung. Alle
erfassten Messdaten werden über die Laufzeit des Messprojektes in Tabellen archiviert.
Die Datenbank muss so übersichtlich sein, dass die Messdaten möglichst leicht ausgewertet werden können. Die Auswertung ist nicht Teil dieser Arbeit.
Das ZUB ist ein Institut für umweltbewusstes Bauen. Das ZUB-Gebäude selbst soll als
Forschungsobjekt dienen. Daher wird eine Leittechnik mit vielen Messpunkten installiert, welche die Klimatisierung und Steuerung des Gebäudes weitgehend übernehmen
soll. Unter dem Begriff Forschungsobjekt ist u.a. zu verstehen, dass die installierten
Messpunkte im Verlauf des Betriebes ausgewertet werden, damit Verbesserungen der
Steuerung und Klimatisierung erzielt werden können, sowie auf bautechnische Verbesserungen zurückgeschlossen werden kann. Die geeignete Anwendung zur Sicherung
und Aufbereitung der Messdaten ist eine Datenbank. Die Auswertung der Daten erfolgt
dann durch den Anwender, indem aus den aufbereiteten Daten weitere Größen berechnet werden und die Inhalte der Tabellen aus der Datenbank (also die Messdaten) so
ausgeben werden, dass diese ein Programm zur Auswertung verarbeiten kann.
1.2 Abweichung zur Aufgabenstellung und weitere Informationen
Die täglichen Messdaten des ZUB werden nicht in ASCII-Dateien zur Verfügung
gestellt, sondern direkt in eine Oracle Tabelle geschrieben.
Das ZUB ist während der Bearbeitung der Aufgabenstellung nicht fertig gestellt worden. Die Leittechnik wurde daher nicht in Betrieb genommen und wichtige Konzepte
fehlen. Die Datenbank musste mit den zur Verfügung stehenden Informationen
programmiert werden.
Die Dokumentation versteht sich als Anwenderdokumentation. Auf die Datenbanksprache SQL (Structured Query Language) und den Aufbau von Oracle selbst wird
nicht eingegangen. Die Literatur (Kap. 7) bietet einen besseren Überblick als eine kurze
Zusammenfassung in dieser Arbeit.
5
Abkürzungen
2 Abkürzungen
2.1 Allgemeine
CAN
Controller Area Network
DB
Datenbank
DDC
Direct Digital Control
ISP
Informationsschwerpunkt
PL/SQL
Procedural Language/SQL
ODBC
Open Database Connection
SQL
Structured Query Language
ZUB
Zentrum für umweltbewusstes Bauen
2.2 Abkürzungen für die Datenbanktabellen
Die Bezeichnungen werden bei Zusammensetzung von hinten nach vorne gelesen.
AUTO
Automatisch
FEHL
Fehlermarkierung
INV
Invers
JAHR
Jahresmittelwerte
MESS
Messbereich
MONAT
Monatsmittelwerte
ROH
Rohdaten
ROHKORR
korrigierte Rohdaten
TAB
Tabelle
TAG
Tagesmittelwerte
TMP
Temporär
Beispiel: <Kennzeichner>_FEHL_AUTO_TAB → <Kennzeichner> Tabelle mit
automatischer Fehlermarkierung
6
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
3 Konzept der Datenbank für das Zentrum für
umweltgerechtes Bauen (ZUB)
Die Datenbank für das ZUB begrenzt sich auf die Sicherung und die erste Aufbereitung
der Messdaten zur Auswertung. Unter der ersten Aufbereitung ist die Anordnung der
Messdaten gemeint und nicht die Berechnung weiterer Größen.
Zum jetzigen Zeitpunkt sind noch keine Konzepte für eine Auswertung bekannt; daher
kann noch keine Aussage über die Weiterverarbeitung getroffen werden. Auch ein
Konzept für Anordnung der Messdaten existiert nur vorläufig (Kap. 3.1.2). Die Datenbank muss so flexibel sein, dass eben die Anordnung der Messpunkte unter Angabe
einiger Informationen automatisch gewährleistet wird. Im Verlaufe des Kapitels wird
sich klären, was damit gemeint ist.
3.1 Grundlegendes
3.1.1 Datenerfassung der Gebäudeleittechnik und der Klimadaten
Messdaten zur Erfassung in der Datenbank werden an zwei Stellen aufgenommen. Einmal die des ZUB selbst und zum anderen Klimadaten, die von einer in unmittelbarer
Nachbarschaft stehenden Wetterstation der Universität Kassel aufgenommen werden.
Die Messpunkte des ZUB werden über einen CAN-Bus (Controller Area Network) dem
Steuerrechner, der DDC (Direct Digital Control) übermittelt.
Die Klimadaten sind über das Netzwerk der Universität Kassel oder ein eigenes Netzwerk verfügbar1. Für die Haustechnikregelung oder eine Auswertung sind die Daten
unerlässlich und müssen dem Steuerrechner zur Verfügung stehen. Abbildung 1 zeigt
die Möglichkeit über den Anschluss an das Universitätsnetzwerk.
1
Diese Angaben sind ohne Gewähr, da zum Zeitpunkt dieser Arbeit die Schnittstelle noch nicht geklärt
ist.
7
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
Wetterstation
ZUB
Universitätsnetzwerk
Technische
Gebäudeausrüstung
Abbildung 1: Datenverkehr über das Universitätsnetzwerk
3.1.2 Informationsschwerpunkte der ZUB Leittechnik
Im ZUB werden die Messpunkte in sogenannten Informationsschwerpunkten (ISP) der
"Gebäudeautomation Informationsliste" dokumentiert [8]. Es gibt bisher 24 ISPs:
ISP
Bezeichnung
00-02
03, 06, 21
04
05
07-19
Raum 0.01 –2.08
Strom
Klimadaten
Sonderräume
Standardräume
20
22
Messräume
Zentrales
Lüftungsgerät
Kanalnetz
Heizung /
Kühlung
23
24
ca. Anzahl Bemerkung
Messpunkte
pro ISP
5
Erdgeschoss, Etage 1, Etage 2
4
13
95
13
Standardräume enthalten zusätzliche
Messwerte von ISP 00 bis ISP 02
122
44
31
54
8
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
Die Tabelle stellt diese Informationsschwerpunkte gebündelt dar. Die Berechnung der
Gesamtanzahl der Messpunkte ergibt sich aus der Anzahl Messpunkte pro ISP mal
Anzahl der ISP. Die Anzahl der Messpunkte beläuft sich auf ca. 700. Je nach Bedarf
kann sich die Anzahl noch ändern. Messpunkte innerhalb der ISP sind beispielsweise:
-
Temperatur
-
Strahlung
-
Luftfeuchtigkeit
-
Ventilzustände (Binär)
-
Kontakte (Binär)
-
Durchfluss
-
Volumina
-
Etc.
Für den Aufbau der Datenbank bietet sich an, Redundanzen der Informationsschwerpunkte zu nutzen, wie sie schon in obiger Tabelle dargestellt wurden.
3.1.3 Redundanzen der Informationsschwerpunkte
Wird jeder ISP in einer autonomen Tabelle gesichert, entstehen 24 Tabellen (Gesamtzahl der ISPs), die nach Ort und Funktionen eingeteilt sind. Es ist jedoch für eine
Auswertung sinnvoller verschiedene ISP´s mit gleicher Funktion zusammenzufassen.
Die Redundanzen in den ISPs werden erstens zur Reduzierung der Anzahl der Tabellen
insgesamt, zweitens zur Reduzierung der Spaltenzahl und drittens zur Verbesserung der
Übersichtlichkeit genutzt. Die Auswertbarkeit wird verbessert.
Es sind Redundanzen bei den Standardräumen ISP 00 – 02 zu erkennen. Nur der Ort
unterscheidet sich, nicht ihre Funktion. Standardräume sind auf alle Etagen des ZUB
verteilt. Spezielle Messpunkte dieser Räume werden zusätzlich in ISP 07 - 19 zusammengefasst. Also werden ISP 00–02 mit ISP 07 - 19 verbunden. Der Hintergrund der
Aufteilung ist, dass nicht in allen Standardräumen die gleichen Daten erfasst werden
bzw. zusätzliche Daten aufgenommen werden müssen. wenn z.B. ein Raum mehr
Fenster oder Türen wie ein anderer hat. Gleiches gilt u.a. für den ISP Strom.
9
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
3.1.4 Bereitstellung der Messdaten, Schnittstelle zur Datenbank
Die Messpunkte des ZUB werden von der DDC in eine oder mehrere dBase Tabellen
geschrieben (dBase ist ein relationales Datenbanksystem) Die Spaltennamen dieser
Tabelle(n) entsprechen den Hardwareadressen der Leittechnik, über die die Messwerte
erfasst werden (die Adressen sind bisher noch nicht festgelegt). Zusätzlich enthält
die/jede Tabelle eine Spalte für das Datum und die Uhrzeit. Handelt es sich um mehrere
Tabellen, werden diese in einer Tabelle zusammengefasst, die alle Spaltennamen für die
Messpunkte plus eine Spalte für das Datum und eine für die Uhrzeit enthält. Diese
Tabelle wird über einen ODBC-Treiber in das Oracle Format konvertiert und soll
mindestens die Messdaten der letzten 14 Wochen enthalten (Abbildung 2). Sie wird
täglich aktualisiert und in die ZUB-DB (ZUB Datenbank) kopiert.
Diese Tabelle heißt ZUB_DATEN_TMP_TAB2 und ist der Ausgangspunkt für die
weitere Verarbeitung.
Rohdaten
(dBase)
Täglichen Messdaten
erfasst von der Leittechnik;
eine oder mehrere Tabellen.
Konvertierung von dBase
nach ORACLE
Oracle
Tabelle
ODBC
Treiber
ZUB_DATEN_TMP_TAB
(Oracle)
Abbildung 2: Schnittstelle zwischen Gebäudeleittechnik und ZUB-DB
3.1.5 Nutzen der Redundanzen der Messpunkte
Redundanzen der ISPs sind in Kap. 3.1.3 beschrieben. Möglichkeiten die Messwerte
abzulegen sind u.a.:
1) Alle Daten ungeordnet in eine Tabelle ablegen.
2
Gelesen: Tabelle mit temporären Messdaten des ZUB
10
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
2) Alle Daten ungeordnet in mehrere Tabellen ablegen.
3) Aufteilung der Daten nach Etagen.
4) Aufteilung der Daten nach Räumen und Funktionen.
Punkt 1 ist nicht zu empfehlen. Die Anzahl der zulässigen Spalten von Oracle ist 1000,
aber durch die Tabellengröße werden Abfragen auf die Tabelle sehr zeitintensiv. Desweiteren ist die Identifizierung mit der Hardwareadresse als Spaltenname umständlich.
Das macht die Auswertung unübersichtlich und schwer wartbar, da selbst kleine
Änderungen in der Tabelle einen großen Aufwand bei der Anpassung des Auswertprogrammes nach sich ziehen.
Punkt 2 entspricht in den Nachteilen Punkt1, außer dass die Zugriffszeit verbessert
wird.
Punkt 3 scheint sinnvoll. Redundanzen der ISPs werden aber auch hier nicht genutzt.
Am Besten ist es - nach Punkt 4 - die Geschosse nach Räumen und Funktionen zusammenzufassen. Es gibt beispielsweise eine bestimmte Anzahl an Standardräumen, in
denen die gleichen Messungen durchgeführt werden. Um die Räume mit gleichen
Messpunkten zusammenzuführen, wird immer eine Tabelle benutzt, die Spalten für das
Datum, die Messpunkte und die Raumnummern enthält. Das reduziert erstens die
Gesamtzahl der Datentabellen und zweitens die Spaltenzahl. So stehen die Daten nicht
mehr nebeneinander sondern untereinander (Abbildung 7).
3.1.6 Bezeichnungen für die Spaltennamen wählen
Wie in Kap. 3.1.4 beschrieben, enthält die Tabelle ZUB_DATEN_TMP_TAB Spaltennamen, die den Hardwareadressen der Leitstation entsprechen. Diese Bezeichnungen
sind hinsichtlich der späteren Auswertung der Messdaten und der Wartbarkeit der
Datenbank nicht sinnvoll und der gewollten Nutzung der Redundanzen hinderlich. Die
Spalten mit der Kennung der Hardwareadresse enthalten implizit den Standort des
Sensors und seine Beschaffenheit (z.B. Temperatur oder Türkontakt). Ort und Beschaffenheit müssen entkoppelt werden. Die neue Kennung (Spaltenname) soll nur noch die
Beschaffenheit des Sensors enthalten; der Ort des Sensors steht in einer zusätzlichen
Spalte mit seiner Raumnummer (Kap. 3.1.5). Diese Aufteilung fördert auch die
Übersichtlichkeit und Wartbarkeit. Es ist einfacher, z.B. die Temperatur (Sensor) als
11
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
Bezeichnung mit der Raumnummer 0_02 (R_Nr) zu wählen, als H00100 (die
Raumnummer muss über die Liste der ISPs ermittelt werden).
In Kapitel 3.2.4 befindet sich die genaue Beschreibung.
3.1.7 Anforderungen an die Leittechnik und die ZUB Datenbank
Hier werden die wichtigsten Anforderungen der Leittechnik zum Einen und zum
Anderen die Anforderungen an die Datenbank aufgelistet, damit ein reibungsloser
Ablauf weitgehend garantiert werden kann.
Anforderungen an die Leittechnik:
-
Jeder Messwert wird im 6 Minuten Takt erfasst.
-
Der abgelegte 6 Minuten Messwert ist ein Mittelwert aus 1 minütigen Messungen (nur bei analogen Werten).
-
Binärwerte werden über die Messdauer von 6 Minuten integriert und als Analogwerte abgelegt3.
-
Die Zeitangabe beginnt für jeden Messwert jeden Tag um 00:00 Uhr und endet
um 23:54 Uhr.
-
Die Daten werden mindestens 1* pro Tag in ZUB_DATEN_TMP_TAB kopiert;
bestenfalls am Tagesende (nach Erfassung des letzten Tageswertes mit 23:54
Uhr)
-
Die ständig aktualisierte Tabelle ZUB_DATEN_TMP_TAB enthält den Messwertsatz in einem Zeitraum von mindestens 14 Wochen.
-
Die Daten von mindestens 14 Wochen müssen gesichert sein.
-
Die Klimadaten werden mit in der Tabelle ZUB_DATEN_TMP_TAB abgelegt.
-
Die Zeiten der von der Leittechnik erfassten Messwerte und der Klimadaten sind
zu synchronisieren.
3
Man integriert den Binärwert, um den prozentualen Zustand innerhalb der 6 Minuten zu erfassen. Man
weiß nicht, wann und wie oft geschaltet wurde, aber es können genauere Aussagen über die Auswirkungen z.B. auf das Raumklima oder den Energieverbrauch getroffen werden.
12
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
ZUB Datenbank:
-
Datum, Zeit und Raumnummer müssen immer vorhanden und eindeutig sein.
-
Bei Ausfall des Universitäts-Servers müssen die gesicherten Daten der Leittechnik nachträglich archivierbar sein.
-
Bei teilweisem Ausfall der Sensorik müssen die verbleibenden Daten archiviert
werden und die fehlenden automatisch in einem Fehlerprotokoll festgehalten
werden.
-
Bei totalem Ausfall der Sensorik muss dies automatisch in einem Fehlerprotokoll festgehalten werden.
-
Überschreitungen des Messbereichs müssen automatisch in einem Fehlerprotokoll festgehalten werden.
-
Es müssen beliebige Messpunkte bzw. ihre Messwerte nachträglich als fehlerhaft markiert werden können.
-
Die Rohdaten enthalten alle Messwerte, die einmal von der Leittechnik in die
Tabelle ZUB_DATEN_TMP_TAB geschrieben wurden.
-
Die korrigierten Rohdaten enthalten alle Daten die nicht manuell als fehlerhaft
markiert wurden.
3.1.8 Begriffe im weiteren Verlauf
Bei relationalen Datenbankmodellen - auf dem Oracle basiert – verwendet man einige
Begrifflichkeiten, die im Verlauf der Arbeit genutzt werden (Abbildung 3). Das Wort
Relation wird im sog. Relationsmodell für Tabelle verwendet. Der Relationsname ist
der Tabellenname. Ein Attribut einer Relation ist die Tabellenspalte (Spaltenname). Und
ein Tupel einer Relation entspricht einer Zeile in einer Tabelle, also Werte von gespeicherten Datensätzen. Ein Attributwert ist ein einzelner gespeicherter Wert innerhalb des
Attributes des Relation [3, 4].
13
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
Abbildung 3: Relationsmodell
3.2 Aufbau und Übersicht
3.2.1 Aufbau der benötigten Datentabellen
Für eine Messwerterfassung sind - an sich - nur die "rohen" (unbearbeiteten) Daten
verlangt. Die Datensicherung macht allerdings nur Sinn, wenn diese Daten ausgewertet
werden. Für eine Auswertung müssen die "rohen" Daten der Datenbank aufbereitet
werden. Das geschieht durch eine automatische Fehlererkennung, die sicher nicht alle
Fehler findet, und durch eine ergänzende manuelle Fehlererkennung, bei der der Administrator die "rohen" Daten sichtet – auch die automatisch erkannten Fehler noch einmal
überprüft.
Speziell in dieser Anwendung werden die Rohdaten in 6 Minuten Intervallen gesichert,
das heißt, es werden täglich 240 Messwerte pro Tag mal ca. 700 Messpunkte gesichert.
Vor der Auswertung müssen Mittelwerte gebildet werden, damit Auswertprogramme
die Daten über Tage, Wochen, Monate und Jahre darstellen können. Die Tabellen mit
Mittelwerten werden in der Datenbank mit angelegt und gefüllt (wöchentliche Mittelwerte werden in dieser DB nicht berechnet). Diese Tabellen besitzen die gleichen
Spalten wie die der Rohdaten – ihre Attributwerte sind Mittelwerte. Es handelt sich um
Abbildungen der Tabelle mit den rohen Daten.
14
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
Muttertabelle
vererbt ihre Spalten
<Tab_Name>
<Tab_Name>_ROH_TAB
Gelesen: Tabelle <Tab_Name>
mit rohen Daten (unbearbeiteten)
Abbildungen von
<Tab_Name>
Fehlerkorrektur
<Tab_Name>_ROHKORR_TAB
<Tab_Name>_TAG_TAB
<Tab_Name>_MONAT_TAB
<Tab_Name>_JAHR_TAB
Abbildung 4: Datentabellen und ihre Abbildungen
Abbildung 4 erschließt nicht nur die Verwendung von Abbildungen einer Tabelle,
sondern auch die Bezeichnungen, die in dieser Datenbank standardisiert wurden. Der
<Tab_Name> ist der eigentliche Tabellenname (z.B. MESSR für Messraum, STDR für
Standardraum etc.). In der Datenbank werden Abbildungen der Tabelle <Tab_Name>
erstellt, die später Messdaten sichern. Die Abbildungen enthalten den <Tab_Name> der
Muttertabelle und werden mit einem Index bzw. Anhang versehen, der verdeutlicht,
welche Daten in diesen Tabellen abgelegt werden.
3.2.2 Aufbau der benötigten Fehlertabellen
Wie schon in Kap. 3.2.1 beschrieben, werden die Fehlertabellen zur Datenaufbereitung
verwendet. Es gibt zwei verschiedene Arten von Fehlertabellen. Einmal die Fehlertabellen zur automatischen Fehlererkennung. Diese besitzen eine Kodierung, die den
15
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
gefundenen Fehler beschreibt. Die anderen sind die inversen Fehlertabellen. Diese
enthalten nur die Werte NULL ("Nichts") für einen fehlerhaften Wert und eine 1 für
einen korrekten Wert. Sie werden später mit den Rohdaten multipliziert. Mehr dazu
befindet sich in den Kapiteln 4.2.3 "Anlegen / Ändern der Datentabellen
(DB_Tabellen_anlegen.sql)" und im Kapitel 5 "Bearbeitung der DB unter Oracle
Forms".
Die inversen Fehlertabellen <Tab_Name>_FEHL_INV_TAB sind keine Abbilder von
<Tab_Name>, wie die Datentabellen. Die Spaltennamen sind zwar identisch zu den
Datentabellen, aber sie besitzen ein anderes Datenformat. Sie benötigen keine Kommastellen oder ähnliches.
Die automatischen Fehlertabellen <Tab_Name>_FEHL_AUTO_TAB haben dasselbe
Spaltenformat wie die Inversen, sind aber ein Sonderfall. Sie enthalten zusätzlich zwei
weitere Spalten. Die Spalten sind Check_Flag und Bearbeiter. Erste zeigt an, ob der
Fehler vom Administrator gesichtet wurde. Die Zweite enthält den Namen des Administrators.
3.2.3 Struktur der Datenbank
Die Datenbank teilt sich in Messdatentabellen, Fehlertabellen und sogenannte Umgebungstabellen auf. Erstere enthalten entweder in irgendeiner Form Messdaten oder als
Fehler markierte Messdaten als Abbildung der Messdaten. Letztere enthalten Informationen über die Relationen und Attribute der Datenbank oder unterstützen die
Verarbeitung der Messdaten.
16
ZEITTAB
Skript:
Zeittab
FEHLER_CODE
fü llt
inträ g
We rte a n
W_
AD
Ta
e rs
tell
to
ü be
im m
t We rt
e
fü llt
Skript:
Ablaufstrg_manuell
rn
de
A NHANG
DATENTABELLEN:
<Tab_Name>_ROH_TAB und
<Tab_Name>_FEHL_A UTO_TAB
ä nd ert
e in
lt H
Skript:
Ablaufstrg_DB_Tabellen_anlegen
ho
R
en
th
ä
ZUORDNUNG
rä
nd
t
lt
Anhängsel:
_TMP_TAB
_FEHL_AUTO_TAB
_FEHL_INV_TAB
_ROH_TAB
_ROHKORR_TAB
_TAG_TAB
_MONAT_TAB
_JAHR_TAB
FEHL_TAB
Skript:
Fuelle_Fehl_inv_tab
DATENTABELLEN:
<Tab_Name>_FEHL_INV_TA B,
<Tab_Name>_ROHKORR_TAB,
<Tab_Name>TAG_TA B,
<Tab_Name>_MONAT_TAB,
<Tab_Name>_JA HR_TAB
er
thä
füllt
E
Be sch re ib t
ü be
Skript:
Ablaufstrg_taeglich
rgib t
ZUB_DATEN_TMP_TAB
p rü ft
t
lt
holt
Anhä
ngsel au
s
Funktion
zuordnung_pruefen
t Fehler in
finde
ho
l
t
We
rte aus
: Zugewiesener interner Name im ZUB
(Spaltennamen aus ZUB_DATEN_TMP_TAB)
R_Nr
: Raumnummer im ZUB
(laut Bauplan + weiteren Index)
Sensor
: Spaltenname in der Datenbank
Format
: Analog- oder Binärwert (A oder B)
Tab_Name : Tabellenname in der Datenbank
(z.B.: Klimadaten)
Minwert : Minimaler Sensorwert für den Messbereich
Maxwert : Maximaler Sensorwert für den Messbereich
en
Alle Datumseinträge, die laut
Spezifikation vorkommen dürfen.
aktuali
siert
prüft
sor aus
erstellt
oder ändert
f
prü
, Sen
aus
äl t
enth
b
e
am
_n
holt E
inträg
e
Hw_Adr
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
Abbildung 5: Mind-Map der Datenbank
17
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
In Abbildung 5 ist das Mind-Mapping der Datenbank zu sehen. Im Mittelpunkt der
Datenbank stehen die Tabellen ZUORDNUNG und ANHANG. Diese Tabelle enthalten
unter anderem alle Informationen über die Relationen und Attribute der Datentabellen,
in denen die Messwerte als Tupel gespeichert werden.
Diese Abbildung wird im Folgenden genau beschrieben. Dabei soll gleichzeitig anhand
eines Beispieles die Funktion und der Ablauf dargestellt werden.
3.2.4 Die Umgebungstabellen ZUORDNUNG und ANHANG
Diese Tabellen bilden das "Herz" der Datenbank. Der Sinn dieser Tabellen besteht
darin, dass alle Datentabellen automatisch anlegt werden können (Kap. 3.2.1) und die
Beziehungen der Tabellen untereinander festgelegt sind. Man erinnere sich, dass die
Datenbank so flexibel sein muss, dass sie einerseits jederzeit erweiterbar und änderbar
sein muss, ohne dass die Hardwareadressen der Messpunkte bisher bekannt sind.
Die Relation ZUORDNUNG enthält folgende Attribute:
Hw_Adr
Attribut der Relation ZUB_DATEN_TMP_TAB
R_Nr
Raumnummer im Gebäude
Sensor
Beschaffenheit des Sensors
Format
Analog- oder Binärwert
Tab_Name
Tabellenname für die Messdaten
Minwert
Minimaler Wert des Messwertes der Spalte Sensor in der Tabelle
<Tab_name>_ROH_TAB (dazu später mehr)
Maxwert
siehe MINWERT
Als Beispiel ist die Tabelle ZUORDNUNG mit folgenden Werten gefüllt.
Hw_Adr
H00100
H00101
H00102
H00103
H00104
H00105
R_Nr
0_01
0_01
0_01
0_01
0_01
0_01
Sensor
T_I
VENTIL_A
VENTIL_B
VENTIL_C
T_OBERFL0
T_OBERFL1
Format
A
B
B
B
A
A
Tab_Name
STDR
STDR
STDR
STDR
STDR
STDR
Minwert Maxwert
-10
50
0
1
0
1
0
1
-10
50
-10
50
18
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
H00106
H00107
H00108
H00109
H00110
H00111
H00112
H00113
H00114
1_02
1_02
1_02
1_02
1_02
1_02
1_02
1_02
1_02
T_I
VENTIL_A
VENTIL_B
VENTIL_C
T_OBERFL0
T_OBERFL1
T_OBERFL0
T_OBERFL1
T_OBERFL2
A
B
B
B
A
A
A
A
A
STDR
STDR
STDR
STDR
STDR
STDR
MESSR
MESSR
MESSR
-10
0
0
0
-10
-10
-10
-10
-10
50
1
1
1
50
50
50
50
50
Ein Tupel von ZUORDNUNG enthält also gleich eine Vielzahl von Informationen. Z.B.
der Attributwert H00100 der Hw_Adr verrät in der Tabelle ZUB_DATEN_TMP_TAB
den Spaltennamen. Weiter ist angeben, dass sich der Sensor im Erdgeschoss im Raum
0_02 (<Etage>_<Raumnummer>) befindet und es sich um einen Temperatursensor
handelt, welcher analog (Format A) die Innentemperatur misst (T für Temperatur, I für
innen) und dieser in einem Standardraum (STDR) installiert ist. Gültige Werte liefert
der Sensor nur im Bereich –10 bis 50 Grad Celsius (falls er für Celsius kalibriert ist).
Die Tabelle ANHANG enthält:
ANHANG
Index bzw. Anhängsel für <Tab_Name> zur Erstellung aller Datentabellen (Kap. 3.2.1).
Anhang
_TMP_TAB
_FEHL_AUTO_TAB
_FEHL_INV_TAB
_ROH_TAB
_ROHKORR_TAB
_TAG_TAB
_MONAT_TAB
_JAHR_TAB
Die Indexe geben Aufschluss über die abgelegten Daten. TAB steht immer für Tabelle.
TMP
temporäre Daten
19
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
FEHL_AUTO automatisch erkannte Fehler
FEHL_INV
inverse Fehlertabelle (mehr dazu ab Kap. 3.2.5.2)
ROH
Rohdaten
ROHKORR
korrigierte Rohdaten
TAG
Tagesmittelwerte
MONAT
Monatsmittelwerte
JAHR
Jahresmittelwerte
Die Tabelle ANHANG verknüpft mit der Tabelle ZUORDNUNG gibt Aufschluss
welche Tabellen sich in der Datenbank befinden und über die Daten in den Datentabellen.
Wenn man wieder mit der Hw_Adr H00100 beginnt, steht erstens Ort und Beschaffenheit des Sensors fest und zweitens, dass sich z.B. in <Tab_Name>_TAG_TAB - hier
STDR_TAG_TAB - die Tagesmittelwerte des Innentemperatursensors im Standardraum
0_02 befinden. Diese Werte sind nicht fehlerhaft markiert worden. Fehlerhafte Werte
stehen nur in den Roh- (<Tab_Name>_ROH_TAB) und temporären Daten
(<Tab_Name>_TMP_TAB).
Zusammenfassend kann gesagt werden, dass die Tabelle ZUORDNUNG alle Hintergrundinformationen enthält und die Tabelle ANHANG die Tabellennamen in der
Tabelle ZUORDNUNG ergänzt und dadurch alle Tabellen mit ihren Attributen bekannt
sind.
3.2.5 Weitere wichtige Umgebungstabellen
3.2.5.1 Die Zeitreferenztabelle ZEITTAB
Für den Betrieb der Datenbank werden noch einige Tabellen benötigt. Vor allem werden Tabellen benötigt, die Informationen über Fehler speichern oder für die Fehlererkennung wichtig sind. Hier werden die Wichtigsten beschrieben.
Die Tabelle ZEITTAB besitzt das Attribut Ref_Zeit (Referenzzeit) und enthält Datumseinträge im 6 Min. Intervall, die für die Messwerte gültig sind4. Das ermöglicht erstens
4
Die Deklaration DATE in Oracle beinhaltet Datum und Uhrzeit im 24 Std.-Format.
20
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
die Suche nach fehlerhaften Datumseinträgen – das sind Abweichungen vom zulässigen
6 Min. Intervall. Zweitens wird die Suche nach fehlenden Datumeinträgen ermöglicht –
z.B. wenn die Leittechnik ausfällt oder die Übertragung gestört ist.
3.2.5.2 Tabellen FEHLER_CODE, FEHL_AUTO_ANZEIGE_TAB und FEHL_TAB
Die Tabelle FEHLER_CODE enthält die Attribute Nr (Nummer) und Fehlerart. In die
automatischen Fehlertabellen wird die Nummer eingetragen, um erstens einen numerischen Wert vorliegen zu haben, der einen schnellen Zugriff erlaubt, zweitens um
Speicherplatz zu sparen. Tritt ein Fehler 1000 mal auf, lohnt es nicht 1000 mal "Messwert nicht vorhanden" in eine Tabelle zu schreiben. Desweiteren sind die Fehler fest
definiert und es treten keine Redundanzen auf. Nach Installation der Datenbank sind
anfangs drei Einträge in dieser Tabelle, die für die automatische Fehlererkennung
verwendet werden.
Nr. Fehlerart
1
Datum nicht vorhanden.
2
Wert ist nicht vorhanden (ev. Sensorausfall).
3
Wert liegt nicht im Messbereich.
Während des Betriebs sollte die Fehlercodetabelle vom Benutzer weiter gefüllt werden,
vor allem wenn er weitere Fehler findet (manuelle Fehlerkontrolle). Ein anderer Benutzer muss wissen, was z.B. die Fehlernummern 4 oder 5 bedeuten.
Die Tabelle FEHL_AUTO_ANZEIGE_TAB fasst die automatisch gefundenen Fehler
aus den Tabellen <Tab_Name>_FEHL_AUTO_TAB zusammen. Der Benutzer erhält
schnell einen Überblick über gefundene Fehler. Er kann diese in den automatischen
Fehlertabellen kontrollieren, ohne alle Datensätze zu durchsuchen (Kap. 3.3.1.3). Das
PL/SQL Skript "Fehl_Auto_Anzeige.sql" durchsucht die Fehlertabellen und schreibt die
Ergebnisse in FEHL_AUTO_ANZEIGE_TAB (das Skript wird bei Bedarf manuell
(Kap. 5.5) gestartet). Die Fehlertabellen enthalten zusätzlich eine Spalte für das
Check_Flag plus eine für den Bearbeiter. Die Fehlereinträge bei denen das Check_Flag
21
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
auf 1 gesetzt wurde und die einen Bearbeiter haben, werden beim Füllen von
FEHL_AUTO_ANZEIGE_TAB nicht berücksichtigt.
Beispiel FEHL_AUTO_ANZ_TAB:
Tabelle
Sensor
R_Nr
Anzahl
Anfang
MESSR
ALLE
ALLE
100
STDR
ALLE
ALLE
240
STDR
T_OBERFL0 0_01
98
STDR
T_OBERFL1 0_01
29
STDR
T_I
1_02
29
STDR
T_I
0_01
30
STDR
T_I
0_01
19
STDR
T_I
0_01
30
29.11.2000
00:06
29.11.2000
00:06
09.12.2000
00:06
09.12.2000
07:06
09.12.2000
07:06
29.11.2000
03:00
30.11.2000
00:06
10.12.2000
00:00
Ende
Fehler Check Bearbeiter
_Nr
_Flag
29.11.2000 1
02:54
29.11.2000 1
02:54
09.12.2000 2
09:54
09.12.2000 2
09:54
09.12.2000 2
09:54
29.11.2000 3
05:54
30.11.2000 3
01:54
10.12.2000 3
02:54
Hier ist die Tabelle schon gefüllt. Fehler wurden in den automatischen Fehlertabellen
von STDR und MESSR gefunden.
Beispiel: In der Fehlertabelle MESSR_FEHL_AUTO_TAB sind ALLE Sensoren in
ALLEN Räumen (R_Nr) ausgefallen bzw. der Fehler 1 aus FEHLER_CODE (Datum
nicht vorhanden) ist 100 mal aufgetreten. Dabei zeigt 100 an, dass das Datum insgesamt
für die Messwerte 100 mal fehlt; die Fehleranzahl berechnet sich pro Messwert. Hat das
Tupel 5 Datenspalten (plus 2 Spalten für Datum und R_Nr), wird bei einem fehlendem
Datum die Anzahl 5 ausgegeben. Das Attribut Check_Flag zeigt an, ob der Fehler
gesichtet wurde. Dieses wird vom Administrator gesetzt (Kap. 5).
Wichtig ist, dass Anfangszeitpunkt und Endzeitpunkt des Fehlers in der Tabelle stehen.
Es ist einstellbar, wie genau FEHL_AUTO_ANZEIGE_TAB gefüllt werden soll. Träte
theoretisch ein Fehler im 12 Min. Takt auf, so würde dieser Eintrag pro Tag 120 mal in
FEHL_AUTO_ANZEIGE_TAB geschrieben. Es reicht die Fehlerart mit frühestem und
letztem Auftreten einmal in die Tabelle zu schreiben. Standardmäßig wurde das Fehler-
22
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
intervall auf 1 Stunde eingestellt5. Das heißt, erst wenn ein Fehler eine Stunde lang
nicht auftritt und dann wieder, erst dann wird er als Fehler neu eingetragen. Es werden
so in der Anzeigetabelle auch korrekte Messwerte als fehlerhaft abgebildet, aber sie
wird übersichtlicher und eine manuelle Überprüfung ist ohnehin nötig.
Bestätigt die Kontrolle, dass es sich tatsächlich um einen Fehler handelt, überträgt der
Administrator den Datensatz in die Tabelle FEHL_TAB. In FEHL_TAB stehen alle als
fehlerhaft erkannten Datensätze, also auch solche, die bei Sichtung der Daten vom
Administrator gefunden wurden. Ist FEHL_TAB vollständig, werden aus ihr die
Tabellen <Tab_Name>_FEHL_INV_TAB gefüllt, die eine 1 für einen korrekten und
eine NULL für einen fehlerhaften Wert beinhalten (NULL ist ungleich 0. Eine NULL
bedeutet soviel wie "leer" oder "nichts"). Multipliziert man die Rohdatentabellen mit
einer solchen Tabelle – beide haben ja die gleichen Spalten – erhält man die korrigierten
Rohdaten.
Beipiel: FEHL_TAB:
LFD
_NR
1
Tab_Name
Sensor
R_Nr
STDR
T_I
0_01
Fehler
_Nr
3
2
STDR
T_I
0_01
3
3
STDR
T_I
0_01
3
4
STDR
T_I
1_02
2
5
STDR
T_OBERFL1
0_01
2
6
STDR
T_OBERFL0
0_01
2
7
STDR
ALLE
ALLE
1
8
MESSR
ALLE
ALLE
1
Anfang
Ende
Bearbeiter Bem.
10.12.2000
00:00
30.11.2000
00:06
29.11.2000
03:00
09.12.2000
07:06
09.12.2000
07:06
09.12.2000
00:06
29.11.2000
00:06
29.11.2000
00:06
10.12.2000
02:54
30.11.2000
01:54
29.11.2000
05:54
09.12.2000
09:54
09.12.2000
09:54
09.12.2000
09:54
29.11.2000
02:54
29.11.2000
02:54
Name
Name
Name
Name
Name
Name
Name
Name
Die Tabellen FEHL_AUTO_ANZEIGE_TAB und FEHL_TAB werden in den nächsten
Kapiteln noch einmal aufgegriffen.
5
PROZEDUR_FORMS_FUELL_FEHL_AUTO_ANZEIGE.SQL Variable: fehlerintervall
Die Prozedur muss nach Änderung neu angelegt werden!
23
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
3.3 Datenfluss und Verarbeitung
Die Architektur des Mind-Map in Abbildung 5 wird hier in der Abfolge des Datenflusses dargestellt (Abbildung 6).
Wie in den vorherigen Kapiteln beschrieben, liegen die Messdaten in der Tabelle
ZUB_DATEN_TMP_TAB mit den Attributen Hw_Adr aus ZUORDNUNG. Die Werte
aus ZUB_DATEN_TMP_TAB werden täglich aktualisiert und in die Tabellen
<Tab_Name>_TMP_TAB aufgeteilt (Abbildung 6). Vorher werden fehlerhafte bzw.
ungenaue Datumseinträge verbessert, um die 6 Minute Intervalle genau einzuhalten
(Kap. 3.3.1.2). Ist beispielsweise eine Messwertserie um 1 Minute "verrutscht", werden
diese Datumseinträge auf das 6 Minuten Intervall aus ZEITTAB (Kap. 3.2.5.1) angepasst.
<Tab_Name>_TMP_TAB enthält die Attribute Sensor und R_Nr aus ZUORDNUNG
plus eine Spalte für das Datum. Die Hw_Adr erhalten hier ihre neue Bezeichnung (Kap.
3.2.4). Die temporären Daten werden 1:1 in die Tabellen <Tab_Name>_ROH_TAB
(Rohdaten) aufgenommen und eventuelle automatisch gefundenen Fehler in die Tabellen <Tab_Name>_FEHL_AUTO_TAB aufgenommen 6.
6
Das geschieht, indem das Skript "Ablaufstrg_taeglich.sql" (tägliche Ablaufsteuerung) gestartet wird.
24
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
Ablaufstrg_taeglich.sql
(Automatisierter Teil)
ZUB_DATEN_TMP_TAB
(Oracle)
Spalten mit Sauternamen
(entsprechen HW_ADR in ZUORDNUNG)
TÄGLICH
Datumseinträge
verbessern
<Tab_Name>_TMP_TAB
Mit korrigierten
Datumseinträgen
Wert vorhanden?
Datum
fehlt?
Messbereich?
<Tab_Name>_ROH_TAB
Tabellen (alle Werte)
Spaltennamen entsprechen
Sensor aus ZUORDNUNG
Eintragen in
<Tab_Name>_FEHL_AUTO_TAB
manuell gefüllt
Ablaufstrg_manuell.sql
(Bei Bedarf starten))
FEHL_TAB
Füllen der inverser
Fehlertabellen
(Fuelle_Fehl_inv_Tab.sql):
Korrekte Werte == 1
Fehlerhafte Werte == NULL
MANUELL
<Tab_Name>_FEHL_INV_TAB
Eintragen in
<Tab_Name>_ROHKORR_TAB
korrigierte
Tageswerte
bzw. Rohdaten
Tagesmittelwerte
Monatsmittelwerte
Jahresmittelwerte
Abbildung 6: Täglicher und manueller Ablauf
Sollen die Datensätze zur Auswertung freigeben werden, muss die Tabelle FEHL_TAB
gefüllt sein (Kap. 3.2.5.2). Aus ihr werden die inversen Fehlertabellen gefüllt und mit
den Rohdatentabellen multipliziert. Man erhält die korrigierten Rohdatentabellen
<Tab_Name>_ROHKORR_TAB (durch Starten von "Fuelle_Fehl_inv_Tab.sql" (Füllen
der inversen Fehlertabellen) werden die inversen Fehlertabellen gefüllt. Danach wird
25
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
durch den Aufruf des Skriptes "Ablaufstrg_manuell.sql" (manuelle Ablaufsteuerung)
die inversen Fehlertabellen mit den Rohdatentabellen multipliziert). Jetzt folgen die
Mittelwertbildungen für die Tages, Monats- und Jahresmittelwerte. Hier endet die
Verarbeitung in der Datenbank. Die Auswertung beginnt.
3.3.1 Automatisierter täglicher Ablauf
Dieses Kapitel beginnt mit einem Beispiel, um den täglichen Datenfluss anschaulich zu
machen. Grundlegend sind hierfür die vorherigen Kapitel und die Abbildung 5 und
Abbildung 6. Dort sind zum einen die Verbindungen zwischen den Tabellen dargestellt,
zum anderen der Datenfluss im Ablaufdiagramm.
3.3.1.1 Ein Beispiel: Täglicher Datenfluss
Die Tabellen in diesem Beispiel wurden in den vorherigen Kapiteln beschrieben.
ZUORDNUNG enthält hier u.a. die Einträge aus Abbildung 7 (siehe auch das Beispiel
in Kap. 3.2.4). Aus den Einträgen werden die Spalten H00100 und H00112 in
ZUB_DATEN_TMP_TAB, die Spalten T_I in STDR_TMP_TAB, STDR_ROH_TAB,
STDR_FEHL_AUTO_TAB und die Spalte T_OBERFL0 in MESSR_TMP_TAB,
MESSR_ROH_TAB, MESS_FEHL_AUTO_TAB angelegt. Das sind die Datentabellen,
die für den täglichen Ablauf wichtig sind (Kap. 3.2 "Aufbau und Übersicht").
Gesetzt den Fall, dass die täglichen Messwerte in ZUB_DATEN_TMP_TAB aufgelaufen sind, werden diese auf die temporären Tabellen STDR_TMP_TAB und
MESSR_TMP_TAB verteilt. Die Verbindung, welche Spalte aus ZUB_DATEN_TMP_TAB welcher aus den Datentabellen zugeordnet ist, findet sich in der Tabelle ZUORDNUNG. Die Werte aus H00100 werden in die Tabelle STDR_TMP_TAB
in Spalte T_I mit der Raumnummer 0_01 eingetragen. Gäbe es – nicht in der Abbildung
– einen Eintrag in ZUORDNUNG, der auch auf die Spalte T_I verweist, aber eine
andere Hw_Adr und Raumnummer besitzt, würden diese Daten in die gleiche Spalte
eingetragen, jedoch mit einer anderen Raumnummer. Die Tabelle wird mit dieser
Vorgehensweise "länger", aber es werden Spalten wie z.B. T_I1, 2 oder 3 gespart, die
die Tabelle "breiter" und unübersichtlicher machen würden. Selbiges gilt für MESSR.
26
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
ZUORDNUNG
Hw_Adr
H00100
Verweis
auf H00100
H00112
R_Nr Sensor
0_01 T_I
Format
A
1_02 T_Oberfl0 A
Tab_Name
STDR
Minwert
10
MESSR
20
Maxwert
50
45
ZUB_DATEN_TMP_TAB
Datum
Uhrzeit
01.01.2001 00:00
H00100
21,3
03.03.2001
21
06:06
H00112
44,4
Verweis
auf T_I
45,1
Daten mit Raumnummer
und neuer Bezeichnung
eintragen
STDR_TMP_TAB
Datum
01.01.2001 00:00
R_Nr
0_01
T_I
21,3
03.03.2001 06:06
0_01
21
STDR_ROH_TAB
Datum
R_Nr
T_I
01.01.2001 00:00
0_01
21,3
03.03.2001 06:06
0_01
21
STDR_FEHL_AUTO_TAB
Datum R_Nr
T_I
MESSR_TMP_TAB
Datum
R_Nr
01.01.2001 00:00 1_02
T_OBERFL0
44,4
03.03.2001 06:06
45,1
1_02
Check_flag Bearbeiter
Maximalwert
überschritten
Eintrag Fehler 3
in Fehlertabelle
MESSR_ROH_TAB
Datum
R_Nr
T_OBERFL0
01.01.2001 00:00
1_02
44,4
03.03.2001 06:06
1_02
45,1
MESSR_FEHL_AUTO_TAB
Datum
R_Nr
03.03.2001 06:06
1_02
T_OBERFL0
3
Check_flag Bearbeiter
NULL
NULL
Abbildung 7: Beispiel für den täglichen Datenfluss
Nachdem die temporären Daten in den Datentabellen (TMP) kopiert wurden, werden
diese 1:1 in den Tabellen STDR_ROH_TAB und MESSR_ROH_TAB gesichert.
Die temporären Daten werden jetzt auf mögliche Fehler geprüft. Das übernimmt die
"Automatische Fehlerkontrolle" in Kap. 3.3.1.3. Für MESSR_FEHL_AUTO_TAB ist
27
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
das in Abbildung 7 dargestellt. Der Messbereich ist in ZUORDNUNG eingetragen und
wird im Falle einer Abweichung in die entsprechende Fehlertabelle mit einer "3" in der
Spalte mit Datum und Raumnummer eingetragen (siehe Tabelle FEHLER_CODE in
Kap. 3.2.5.2).
3.3.1.2 Verbessern ungenauer Datumseinträge aus ZUB_DATEN_TMP_TAB
Nachdem die Messdaten aktualisiert wurden, werden die Datumseinträge kontrolliert.
Das Datum aus ZUB_DATEN_TMP_TAB liegt noch nicht im Oracle Format vor. Da
ZUB_DATEN_TMP_TAB aus dBase-Tabellen konvertiert wurde, enthält diese Tabelle
das Datumformat aus dBase. Dort sind Datum und Uhrzeit jeweils in einer gesonderten
Spalte vorhanden. Oracle dagegen sichert unter der Deklaration DATE das Datum und
die Uhrzeit in einer einzigen Variablen.
Der Ablauf dieser Funktion ist in Abbildung 8 ersichtlich. Die Grundlage ist der
Vergleich zwischen den Einträgen aus ZEITTAB und der Datentabelle. Realisiert ist
diese Funktion, indem das Anfangs- und Enddatum aus ZUB_DATEN_TMP_TAB
gelesen wird und dieser Abschnitt aus ZEITTAB selektiert wird. Danach kann man
direkt vergleichen, ob es Abweichungen in den Datumseinträgen gibt (das übernimmt
die Funktion "Prozedur_Datum_verbessern.sql").
Falls mehrere Datumseinträge hintereinander ungenau sind, wird untersucht, welcher
Wert logisch der nähere ist. Dabei kann ein ungenaues Datum mehr als die Hälfte eines
Intervalls abweichen (> 3 Minuten) und es wird trotzdem richtig zugeordnet. Liegt
beispielsweise ein Wert 1 Minute vor der Referenzzeit und einer 1 Minute danach,
werden beide Werte übernommen. Bei einer Datumkorrektur, die die Werte immer auf
das naheliegende Datum setzt, ginge ein Wert von beiden verloren, da sie auf die
gleiche Referenzzeit verwiesen.
28
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
ZUB_DATEN_TMP_TAB
Tabelle mit den aktuellen Messdaten
Datum,
Uhrzeit
(CHAR)
Anfangs- und Enddatum bestimmen
Konvertieren in
Oracle Format
+
Datum
(Oracle Format)
Gibt es Datumseinträge, die
Datum
in ZUB_DATEN_TMP_TAB
gefunden? sind, aber nicht in ZEITTAB?
Diese Datums sind falsch.
JA
NEIN
ENDE
Werte aus ZEITTAB
lesen
Nächstes Falsche Datumseinauslesen träge einzeln auslesen
NEIN
ENDE
Gefunden?
JA
Referenzdatums
auslesen
Es werden aus ZEITTAB die richtigen
Datumseinträge vor und nach dem
falschen Datum gelesen.
Referenzdatum vor
falschem Datum
NEIN
Schon
vorhanden?
JA
Ist das erste richtige Datum aus ZEITTAB
in ZUB_DATEN_TMP_TAB vorhanden?
Wenn nein, nehme das richtige Datum davor;
wenn ja, nehme das richtige Datum danach;
ersetze das Datum in ZUB_DATEN_TMP_TAB.
Referenzdatum nach
falschem Datum
Schon
vorhanden?
JA
NEIN
ZUB_DATEN_TMP_TAB
aktualisieren
Das falsche Datum in
ZUB_DATEN_TMP_TAB
wird durch das Refenenzdatum ersetzt.
Abbildung 8: Verbessern ungenauer Datumseinträge in ZUB_DATEN_TMP_TAB
29
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
Der Nachteil eines solchen Vorgehens kommt zum Vorschein, wenn erst Datumseinträge vollständig fehlen und dann ein ungenaues Datum auftritt. Weicht das
ungenaue Datum 1 Minute von der Referenzzeit ab, würde es in so einem Fall einer
Referenzzeit früher zugeordnet und auf dem Wert 5 Minuten früher gesetzt. Dieser
Fehler ist allerdings unwahrscheinlich.
3.3.1.3 Automatische Fehlerkontrolle
In Abbildung 9 ist wieder der gesamte tägliche Datenfluss dargestellt, nur diesmal mit
besonderem Blick auf die automatische Fehlerkontrolle (Skript "Fehler_eintragen.sql").
Zuerst werden in ZUB_DATEN_TMP_TAB die ungenauen Datumseinträge verbessert
(siehe vorherigen Abschnitt) und in die temporären Datentabellen und Rohdatentabellen
übernommen. Bis hierhin wurde alles schon beschrieben. Die Tabellen mit temporären
Daten <Tab_Name>_TMP_TAB werden jetzt automatisch untersucht. Gefundene
Fehler werden in die Tabellen <Tab_Name>_FEHL_AUTO_TAB eingetragen.
Zurst wird geprüft, ob alle Datumseinträge vorhanden sind (Fehler "1" in FEHLER_CODE Kap. 3.2.5.1). Das geschieht ähnlich wie bei dem Verbessern der ungenauen Datumseinträge. Fehlt das Datum oder die Uhrzeit in ZUB_DATEN_TMP_TAB,
fehlt es für alle Räume und alle Sensoren, da hier alle Messdaten gesammelt sind. In
diesem Fall werden alle Messdatenfehlerspalten der automatischen Fehlertabellen mit
einer 1 markiert.
Die zweite Prüfung ist, ob es eine Sensorausfall oder ähnliches gegeben hat. Das heißt,
dass Datum und die Raumnummer vorhanden sind, aber ein oder mehrere Messwerte
fehlen. Dieser Fehler wird mit einer 2 quittiert.
Die letzte Prüfung ist die des Messbereiches. Hier wird geprüft, ob die Werte in dem
Bereich liegen, der in ZUORDNUNG (Kap. 3.2.4) in Minwert und Maxwert angegeben
ist. Liegt der Messwert nicht in diesem Bereich, wird der Fehler 3 eingetragen.
30
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
Prozedur:
datum_verbessern()
ZUORDNUNG
Siehe Abbildung:
Prozedur: datum_verbessern
Tabellenname (Tab_Name),
Spaltenname (Sensor)
Raumnummer (R_Nr),
Sautername (Hw_Adr)
Minimalwert (Minwert)
Maximalwert (Maxwert)
Neuestes Datum
bei bestimmter R_Nr
<Tab_Name>_ROH_TAB
<Tab_Name> _TMP_TAB
Eintragen in
Rohdatentabelle
Prüfen, ob alle Datums vorhanden sind.
Fehler “1” eintragen in
<Tab_Name>_FEHL_AUTO_TAB
NEIN
Restliche Werte
Fehler “2” eitragen in
<Tab_Name>_FEHL_AUTO_TAB
NEIN
Restliche Werte
Fehler “3” eintragen in
<Tab_Name>_FEHL_AUTO_TAB
NEIN
Restliche Werte
Datum
vorhanden?
JA
ZEITTAB
Zeittabelle mit Refernzdatums
Prüfen, ob alle Werte vorhanden sind
Werte
vorhanden?
JA
Messbereich?
Zwischen
Min- und Maxwert?
JA
ENDE
Abbildung 9: Automatische Fehlerkontrolle
3.3.2 Manueller Ablauf mit Blick auf die Tabelle FEHL_TAB
Die manuelle Ablaufsteuerung wird gestartet, wenn die inversen Fehlertabellen aus
Tabelle FEHL_TAB (Kap. 3.2.5.2) gefüllt sind (Skript "Fuelle_Fehl_inv_tab.sql").
Hier soll auf das Füllen der inversen Fehlertabellen <Tab_Name>_FEHL_INV_TAB
eingegangen werden; der Rest – sprich die Mittelwertbildung - wird im folgenden
Kapitel beschrieben.
Realisiert wird dieser Prozess, indem erst einmal alle Datumseinträge und Raumnummern aus <Tab_Name>_ROH_TAB übernommen werden und in alle übrigen Spalten
31
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
des Tupels eine 1 eingetragen wird7. Die fehlerhaften Werte werden danach auf NULL
aktualisiert.
Hier sei noch einmal die Information in der Tabelle FEHL_TAB aufgegriffen. Am
einfachsten ist die Beschreibung anhand eines Beispieles.
LFD
_Nr
1
Tab_Name
Sensor
R_Nr
STDR
T_I
0_01
Fehler
_Nr
3
Anfang
Ende
Bearbeiter Bem.
10.12.2000 10.12.2000 Name
00:00
02:54
Die Lfd_Nr, die Fehlernummer (Fehler_Nr), der Bearbeiter und die Bemerkung (Bem.)
interessieren nur den Administrator.
Tab_Name, Sensor, R_Nr, Anfang und Ende sind die relevanten Informationen zum
Füllen der inversen Fehlertabellen.
STDR (Standardraum), T_I (Innentemperatur), Raum 0_01 hat irgendeinen Fehler
zwischen dem 10.12.2000 ab 00:00 Uhr bis zum 10.12.2000 ab 02:54 Uhr (s.o.). Diese
Werte werden mit einer NULL überschrieben; alle anderen dieses Wertes bleiben auf 1
(korrekt).
Das Enddatum kann auch freigelassen werden (NULL sein). Es wird dann so behandelt,
als wäre es der 01.01.2050 00:00 Uhr. Dieses Datum wurde frei gewählt und kann noch
geändert werden. Ein solcher Fall tritt ein, wenn der Fehler bekannt ist, aber nicht der
Zeitpunkt seiner Behebung.
FEHL_TAB kann als Eintrag"ALLE" in Sensor und R_Nr enthalten oder diese können
genau spezifiziert sein. Das bedeutet, es sind vier verschiedene Prozesse zu beachten.
7
Mit der Option DEFAULT 1 auf eine Spalte beim Anlegen der Tabelle, wird diese automatisch mit
einer 1 gefüllt, wenn ein beliebiger Wert – außer NULL - in eine andere Spalte des Tupels eingetragen
wurde.
32
Konzept der Datenbank für das Zentrum für umweltgerechtes Bauen (ZUB)
Möglichkeiten
Tabelle
Sensor
R_Nr
1
<Tab_Name>
Angegeben
Angegeben
2
<Tab_Name>
ALLE
Angegeben
z.B. (STDR)
3
<Tab_Name>
(z.B. 0_01)
Angegeben
ALLE
(z.B. T_I)
4
<Tab_Name>
ALLE
ALLE
Möglichkeit 1 wurde oben beschrieben. Wir gehen weiter davon aus, dass die inversen
Fehlertabellen alle Raumnummern und Datumeinträge enthalten.
Möglichkeit 2 zeigt an, dass "ALLE" Sensoren des Raumes z.B. 0_01 fehlerhaft sind.
Das heißt, die Zeilen zwischen Anfang- und Enddatum werden für die Raumnummer in
<Tab_Name>_FEHL_INV_TAB (z.B. STDR_FEHL_INV_TAB) entfernt.
Möglichkeit 3 sagt, dass in allen Räumen der Sensor z.B. T_I falsch ist. Folglich wird
der Inhalt der Spalte T_I in den inversen Fehlertabellen - zwischen dem Anfangs- und
Enddatum in STDR_FEHL_INV_TAB - auf NULL gesetzt.
Möglichkeit 4 löscht alle Datumseinträge zwischen dem Anfangs- und dem Enddatum
in STDR_FEHL_INV_TAB. Das geschieht, wenn ein Datum oder eine Uhrzeit in
ZUB_DATEN_TMP_TAB fehlen.
33
Realisierung
4 Realisierung
Dieses Kapitel beschreibt die Realisierung der Datenbank mit ihren Skripten und
Meldungen. Besonderes Augenmerk wird auf die Konsistenz aller Tabellen gelegt.
Es soll möglichst wenig auf die Programmierung in SQL, PL/SQL und DBMS_SQL
eingegangen werden.
DBMS_SQL ist dynamisches PL/SQL, das heißt, Anweisungen werden zur Laufzeit
geparst und dann ausgeführt. Diese Art der Programmierung musste oft angewendet
werden, da die Tabellen erst während der Laufzeit angelegt bzw. geändert werden, so
dass die Einträge aus ZUORDNUNG weitmöglichst konsistent sind (siehe Kap. 4.3).
Die Literatur behandelt dieses oft unzureichend. Am ausführlichsten ist DBMS_SQL in
"Documentation Library for Oracle8 Release 8.0.5" [1] beschrieben. Es ist dort unter "> Application Development -> Oracle8 Application Developer's Guide Release 8.0 ->
14 Using Dynamic SQL" zu finden.
4.1 Anlegen der Datenbank
4.1.1 Verzeichnisse
Die Skripte der Datenbank sind auf mehere Verzeichnisse verteilt.
Hauptverzeichnis D:\ZUB_DB
Unterverzeichnisse
...\SQL
Skripte für das Anlegen des täglichen und manuellen Ablaufs
der Datenbank.
...\Forms
Enthält die Eingabemaske unter Oracle Forms und die Skripte
zur Ansicht unter der Form´s Maske.
Enthält auch das Skript "Fuelle_Fehl_Inv_Tab.sql", welches
aus der Maske gestartet wird. Dazu mehr in Kap. 5.
...\Meldungen Hier werden alle Meldungen gesammelt, die von verschiedenen
Skripten ausgeben werden. Sie werden in den folgenden Kapiteln
beschrieben.
...\Test
Skripte für den Test der Datenbank. Beim Betrieb der DB sind
34
Realisierung
diese nicht relevant.
...\DB_Indx
Enthält drei physikalische Dateien ("Tablespace"), in denen
die Benutzerdaten, Indexe und die Messdaten abgelegt sind.
Soll die Datenbank in einem anderen Verzeichnis angelegt werden, müssen die SQL
Skripte und die Kodierung unter Forms durchsucht werden und das Hauptverzeichnis
dort geändert werden. Die Unterverzeichnisse sollten gleich bleiben. Die folgenden
Abschnitte müssen dann so gelesen werden, als wäre das Hauptverzeichnis ein anderes.
!!! Das Ändern der Verzeichnisse funktioniert nur vor dem Anlegen der Datenbank. Die
Messdaten und Indexe gehen sonst verloren !!!
4.1.2 Vorbereitung
Um die Umgebungstabellen und alle Datentabellen anzulegen, sind nach Installation
von Oracle zwei zusätzliche TABLESPACE [2, 4] unter dem Verzeichnis d:\ZUB_DB\
Indx_DB mit den Namen "ZUB_DATEN" und "INDX" anzulegen. "INDX" enthält
Indexe auf Tabellen sowie die Constraints [1 - 6] der Tabellen. Ein gut angelegter Index
auf eine Tabelle verbessert die Performance. "ZUB_DATEN" enthält die Messdaten.
Der TABLESPACE "USR" wird in das Verzeichnis verschoben. Er enthält die Benutzerinformationen. Alle drei Änderungen werden am besten mit dem "Enterprise
Manager" von Oracle [1] vorgenommen.
4.1.3 Die Datenbank neu anlegen (Ablaufstrg_DB_neu_anlegen.sql)
Die Skripte mit dem Präfix "Ablaufstrg_" steuern den Ablauf der Verarbeitung und
rufen ihrerseits Skripte auf. Beim Anlegen der Datenbank muss sehr vorsichtig vorgegangen werden. Hier wird die Grundlage für die Funktionstüchtigkeit gelegt. Ist die
Datenbank falsch angelegt und sind Messdaten abgespeichert, ist eine Änderung bzw.
Korrektur sehr schwierig und zeitintensiv. Wichtig für das Anlegen ist das Skript
"Zuordnung.sql" (Abbildung 10). Hier sind Einträge, aus denen ZUB_DATEN_TMP
geändert wird und alle Datentabellen angelegt werden. "Zuordnung.sql" enthält die
Einträge für die Tabelle ZUORDNUNG, die in "Umgebungstabellen.sql" angelegt wird.
"Umgebungstabellen.sql" löscht alle Umgebungstabellen und legt sie neu an. In
"InitUmgebungstabellen.sql" werden einige Tabellen initialisiert. Die wichtigsten sind
35
Realisierung
ANHANG (Kap. 3.2.4) und FEHLER_CODE. Ist ZUORDNUNG gefüllt, werden alle
notwendigen Funktionen und Prozeduren für den Betrieb angelegt [1, 2, 4].
DB_Tabellen_loeschen.sql
Umgebungstabellen.sql
InitUmgebungstabellen.sql
Zuordnung.sql
Datenbank_neu_anlegen.txt
Dateien mit Informationen
im Verzeichnis “Meldungen”
Datenbanktabellen.txt
Funktionen und
Prozeduren anlegen
DB_Tabellen_anlegen.sql
Fehler?
NEIN
Ende
JA
Löschen aller Datentabellen
<Tab_Name> und die Tabellen
<Tab_Name> plus <Anhang>
Löschen und neu anlegen
aller Umgebungstabellen,
inkl. ZUORDNUNG und
ZUB_DATEN_TMP_TAB
Initialisieren der Umgebungstabellen
FEHLER_CODE
ANHANG
ZUORDNUNG_GEAENDERT
Vorbereite Tabelleneinträge für
ZUORDNUNG.
Anlegen aller Funktionen und Prozeduren, die während des Ablaufs der
Datenbankbenötigt werden.
Anlegen der Datentabellen
<Tab_Name> und <Tab_Name>
plus Anhang bei erfolgreicher
Prüfung von ZUORDNUNG..
Wenn ein Fehler beim Anlegen der
Tabellen aufgetreten ist, muss der
Fehler in ZUORDNUNG korrigiert
und das Skript erneut gestartet
werden.
Das Skript Zuordnung.sql darf man
nicht gesondert ausführen. U nter
Umständen können die Datenbanktabellen dann nicht mehr
automatisch gelöscht werden.
Abbildung 10: Anlegen der Datenbank
Der Leser wird sich fragen, warum die Datentabellen zuerst gelöscht werden, obwohl
sie ja noch nicht existieren ("DB_Tabellen_loeschen.sql")? Das liegt an dem Skript
"DB_Tabellen_anlegen.sql", dem ein eigenes Kapitel gewidmet ist. Dort wird versucht
die Datenbanktabellen anzulegen. ZUORDNUNG muss fehlerfrei sein, bevor die
Tabellen angelegt werden. ZUORDNUNG kann nur auf Syntax und Plausibilität geprüft
werden, nicht aber auf einen versehentlichen Eintrag wie STRD anstelle von STDR im
der Spalte Tab_Name. Diese Ungenauigkeit hat zur Folge, dass die Tabellen STRD und
ihre Abbildungen angelegt werden. Der Administrator schaut sich im Verzeichnis
36
Realisierung
...\Meldungen die Dateien "Datenbank_neu_anlegen.txt" und "Datenbanktabellen.txt"
an und prüft diese auf Fehlermeldungen. "Datenbanktabellen.txt" enthält alle Fehler aus
der Prüfung von ZUORDNUNG, bzw. alle angelegten Datentabellen aus ZUORDNUNG. Findet der Administrator einen Fehler oder eine versehentlich angelegte
Tabelle, ändert er "Zuordnung.sql" (ohne es auszuführen) und startet das Skript
"Ablaufstrg_DB_neu_anlegen.sql" erneut. Alle Tabellen werden gelöscht und neu
angelegt. Dieser Vorgang wiederholt sich bis der Administrator sicher ist, dass alle
Tabelle korrekt angelegt wurden.
ACHTUNG:
Am Ende sollten die Dateien "DB_Tabellen_loeschen.sql", "Zuordnung.sql", "Umgebungstabellen.sql" und "InitUmgebungstabellen.sql" gesichert und aus dem Verzeichnis
entfernt werden, damit nicht versehentlich eines dieser Skripte gestartet wird und es zu
einem Datenverlust kommt!
37
Realisierung
4.2 Datenbanktabellen anlegen/ändern
(Ablaufstrg_DB_Tabellen_anlegen.sql)
Meldungen über Fehler oder Erfolg sind in der Datei "Datenbanktabellen.txt" im
Verzeichnis ...\Meldungen zu finden.
4.2.1 Übersicht
Das Skript "DB_Tabelle_anlegen.sql" ist ein wichtiger Teil der Datenbank. Es ist für
die Konsistenz der Datenbanktabellen, wie sie in ZUORDNUNG stehen, verantwortlich. Der Ablauf ist in Abbildung 11 dargestellt.
Einerseits werden die Datentabellen angelegt bzw. geändert, andererseits wird die
Tabelle ZUB_DATEN_TMP_TAB geändert. ZUB_DATEN_TMP_TAB wurde in den
Umgebungstabellen mit den Attributen Datum und Uhrzeit angelegt (Kap. 4.1.3). Die
zukünftigen Attribute von ZUB_TMP_DATEN müssen den Attributwerten des Attributes Hw_Adr aus ZUORDNUNG entsprechen, damit alle Daten übernommen werden.
Genauso verhält es sich mit den Datentabellen. Tab_Name, Sensor, Format aus
ZUORDNUNG und der Inhalt der Tabelle ANHANG sind notwendig, diese Tabellen
konsistent zu ZUB_DATEN_TMP_TAB zu gestalten (Kap. 4.2.3).
Bevor das geschieht, muss ZUORDNUNG vorgeprüft werden, damit Obiges gewährleistet ist (Kap. 4.2.2).
38
Realisierung
ZUORDNUNG
zuordnung_pruefen( Aufruf mit FLAG ‘ANLEGEN’
‘ANLEGEN’)
siehe Funktion zuordnung_pruefen()
ZUB_DATEN_TMP_TAB
aus ZUORDNUNG
ändern
NEIN
Fehler
gemeldet?
JA
Keine Tabellen
anlegen oder ändern.
1) Fehlerausgabe
2) ENDE
zuordnung_pruefen(
‘ALLES’)
Fehler
gemeldet?
JA
NEIN
1) Fehlerausgabe
Keine Tabellen
2) ENDE
anlegen oder ändern.
Hier dürften nach dem Konzept keine Fehler mehr auftauchen;
Prüfung gilt der Datensicherheit und -konsistenz
Detailierte Dargestellung unter Abbildung 13: Nächster
Tabellenname
Ändern und Anlegen der Datentabellen
(DB_Tabellen_Anlegen.sql)
ZUORDNUNG
Ende
NEIN
Gefunden?
JA
Tabellen anlegen
mit allen Spalten
Spalten einfügen
NEIN
NEIN
Tabelle
vorhanden?
JA
Tabellennamen
Daten- und
Fehlertabellen
SpaltenSpalte namen
vorhanden?
JA
Abbildung 11: Übersicht Ablaufsteuerung Tabellen anlegen/ändern
4.2.2 Zuordnung prüfen (Funktion_Zuordnung_pruefen.sql)
Die Funktion "zuordnung_pruefen(<option>)" wird aufgerufen, bevor irgendwelche
Tabellen geändert oder angelegt werden. Sie besteht aus fünf Teilen (Abbildung 12).
39
Realisierung
ZUORDNUNG
NEIN
Hw_Adr
mehrfach?
JA
Fehlerausgabe
Fehler Bit 1
Wurde ein Spalte aus
ZUB_DATEN_TMP_TAB mehrfach eingegeben?
NEIN
R_Nr,
Sensor?
JA
Fehlerausgabe
Fehler Bit 2
Sind gleichzeitig Raumnummern
und Sensoren gleich?
NEIN
Spalten
in?
Fehlerausgabe
Fehler Bit 3
JA
Sind alle Hw_Adr aus
ZUORDNUNG in ZUB_DATEN_TMP_TAB?
JA
FLAG =
‘ANLEGEN’?
Wird bei Aufruf der Funktion
‘ANLEGEN’übergeben, wird diese
Prüfung übersprungen.
NEIN
JA
Spalten
Fehlerausgabe
in?
Fehler Bit 4
Sind alle Spalten aus
ZUB_DATEN_TMP_TAB in ZUORDNUNG?
NEIN
NEIN
Syntax
ok?
JA
Fehlerausgabe
Fehler Bit 5
Sind andere Zeichen wie 0-9, A-Z oder
ein _ in ZUORDNUNG?
RETURN 0
NEIN
Fehler?
JA
Sind oben Fehler aufgetreten?
ENDE
RETURN
Fehler-Bits
Fehler addieren
und ausgeben.
Bei Fehlern werden keine DB
Tabellen angelegt oder verändert.
Abbildung 12: ZUORDNUNG auf mögliche Fehler prüfen
40
Realisierung
Schritt 1
ist die Prüfung, ob der Attributwert aus Hw_Adr mehrmals vorkommt. Ist das
der Fall, müsste diese Spalte mehrfach in ZUB_DATEN_TMP_TAB angelegt
werden. Da das nicht sein kann, wird ein Fehler gesetzt.
Schritt 2
prüft in ZUORDNUNG die Attributwerte aus R_Nr und Sensor. Kommt ein
Attributwert aus Sensor doppelt vor, ist das nicht unbedingt falsch. Z.B. werden
in den Standardräumen die Innentemperaturen mit den gleichen Sensoren
gemessen. Ein Fehler ist es nur, wenn sich dieser Sensor mehrmals im gleichen
Raum befindet. Dann müsste die Spalte mit dem gleichen Namen mehrfach
angelegt werden, was nicht möglich ist.
Schritt 3
ist eine Gegenprüfung von ZUB_DATEN_TMP_TAB und ZUORDNUNG. Es
wird abgefragt, welche Attribute ZUB_DATEN_TMP_TAB besitzt und welche
Attributwerte unter Hw_Adr in ZUORDNUNG stehen. Diese werden verglichen.
Hier wird nur geprüft, ob sich andere Spalten in ZUB_DATEN_TMP_TAB
befinden, als sich Verweise in ZUORDNUNG befinden. In ZUORDNUNG
können dabei mehr Verweise stehen als Spalten in ZUB_DATEN_TMP_TAB.
Das heißt, es wird eine Untermenge abgefragt.
Schritt 4
ist invers zu Schritt 3. Hier können mehr Spalten in ZUB_DATEN_TMP_TAB
sein, als in ZUORDNUNG angegeben. Sollten es weniger sein, wird ein Fehler
gemeldet. Diese Prüfung muss übersprungen werden, wenn ZUB_DATEN_TMP_TAB geändert werden soll. Das ist logisch, denn wenn ein neuer
Eintrag in ZUORDNUNG steht, kann diese Spalte schließlich noch nicht in
ZUB_DATEN_TMP_TAB stehen.
Schritt 3 und Schritt 4 ergänzen sich, sodass beide Tabellen konsistent sein
müssen.
Schritt 5
ist die Abschlussprüfung. Hier werden alle Spalten aus ZUORDNUNG geprüft
die keine numerischen Werte enthalten (alle außer Minwert, Maxwert). In
41
Realisierung
ZUORDNUNG sind nur Zeichen von 0-9,A-Z und der Unterstrich "_" zulässig.
Kommen andere Zeichen vor, wird ein Fehler gemeldet.
Wird eine anderer Wert als "0" von dieser Funktion zurückgegeben, werden keine
Tabellen angelegt oder verändert.
"Zuordnung_pruefen(<option>)" wird bei jedem Ändern oder Anlegen von Tabellen
zweimal aufgerufen. Bei der ersten Prüfung, wird die <option> 'ANLEGEN' übergeben.
Schritt 4 wird übersprungen und - falls keine anderen Fehler auftreten – die Tabelle
ZUB_DATEN_TMP_TAB geändert. Danach werden alle Prüfungen noch einmal
ausgeführt. Im fehlerfreien Fall werden dann die Datentabellen angelegt oder verändert.
Hier sei noch einmal darauf hingewiesen, dass diese Prüfungen nicht vor versehentlichen Eingaben schützen. Sind die Tabellen erst einmal geändert, können diese
Änderungen nicht mehr bzw. nur unter großem Aufwand zurückgenommen werden.
4.2.3 Anlegen / Ändern der Datentabellen (DB_Tabellen_anlegen.sql)
Hier wird der schraffierte Bereich aus Abbildung 11 genauer betrachtet.
Zuerst werden die Tabellennamen <Tab_Name> aus ZUORDNUNG selektiert. Gibt es
diesen Tabellennamen noch nicht, müssen alle erforderlichen Datentabellen angelegt
werden (Abbildung 13 links). Als ersten Schritt werden die Tabellen <Tab_Name>,
<Tab_Name>_FEHL_AUTO_TAB, <Tab_Name>_FEHL_INV_TAB mit den Spalten
Datum und Raumnummer R_Nr angelegt. Zusätzlich werden in den Tabellen
<Tab_Name>_FEHL_AUTO_TAB Spalten Check_Flag und Bearbeiter eingefügt
(Verwendung unter Kap. 5.1). Die Fehlertabellen werden gleichzeitig mit <Tab_Name>
angelegt, da das Format der in ZUORDNUNG referenzierten Spalte (Sensor) nicht dem
der übrigen Messdatentabellen entspricht. Das Format dieser Spalten ist NUMBER(2)8.
8
NUMBER(2) bedeutet Zahlen von -99-99 ohne Komma. Es handelt sich also um ein spezielles Integer-
Format.
42
Realisierung
DB_TAB_ANLEGEN
(Datenbanktabellen anlegen)
Nächster
Tabellenname (<Tab_Name>),
Spaltenname (Sensor)
Spalten:
Tabelle mit
Datum, R_Nr <Tab_Name> anlegen
NEIN
Tabellen anlegen
<T ab_Name>_FEHL_AUTO_TAB
<T ab_Name>_FEHL_INV_TAB
Sensor aus
Spaltenname ZUORDNUNG
entspicht Sensor
Alle
bearbeitet?
ZUORDNUNG
Tabelle
vorhanden?
Spalten:
Datum, R_Nr,
Check_Flag,
Bearbeiter
Alle übrigen Spalten mit
Format NUMBER(2)
(siehe unten))
Spalten:
Datum, R_Nr
Tabellen kopieren von <Tab_Name>
<Tab_Name> _TMP_TAB
<Tab_Name> _ROH_TAB
<Tab_Name> _ROHKORR_TAB
<Tab_Name> _TAG_TAB
<Tab_Name> _MONAT_TAB
<Tab_Name> _JAHR_TAB
JA
NEIN
Spalte Sensor anlegen in
<T ab_Name> _FEHL_AUTO_TAB
<T ab_Name>_FEHL_INV_TAB
(Format NUMBER(2))
NEIN
Binärwert
Format
NUMBER(1)
Analogwert?
NEIN
JA
Analogwert
Format
NUMBER(5,2)
nächste
Spalte Sensor
auswählen
Spalte
vorhanden?
Spalte Sensor anlegen in
<Tab_Name> _FEHL_AUTO_TAB
<T ab_Name>_FEHL_INV_TAB
(Format NUMBER(2))
NEIN
Binärwert
Spalte Sensor mit gewählten
Format anlegen in <T ab_Name>
JA
Format
NUMBER(1)
Analogwert?
JA
JA
Analogwert
Format
NUMBER(5,2)
Spalte Sensor einfügen in
<Tab_Name>_TMP_TAB
<Tab_Name>_ROH_TAB
<Tab_Name>_ROHKORR_TAB
<Tab_Name>_TAG_TAB
<Tab_Name>_MONAT_TAB
<Tab_Name>_JAHR_TAB
Alle NEIN
bearbeitet?
JA
Abbildung 13: Ändern und Anlegen der Datentabellen (DB_Tabellen_Anlegen.sql)
Jetzt werden die Attributwerte Sensor aus ZUORDNUNG in die Tabelle <Tab_Name>
eingefügt. Weiter ist in ZUORDNUNG unter dem Attribut Format angegeben, ob es
43
Realisierung
sich um einen Analog- oder Binärwert handelt. Ist es ein Analogwert, wird die Spalte
mit dem Format NUMBER(5,2) angelegt. Das heißt, die Zahl kann insgesamt fünf
Zeichen lang sein – ohne Berücksichtigung des Vorzeichens -, wobei 2 Zeichen
Nachkommastellen sind. Das entspricht einem Wertebereich von –999.99 bis 999.99.
Handelt es sich um einen Binärwert, ist das Format NUMBER(1) mit einem Wertebereich9 von –9 bis 9. Sind alle Spalten eingetragen, werden die übrigen Datentabellen
als Abbild von <Tab_Name> erstellt und der nächste Tabellenname ausgewählt. Die
Prozedur wiederholt sich, wenn der nächste gefundene Name wieder eine noch nicht
angelegte Tabelle ist.
Ist die Tabelle allerdings schon vorhanden, werden die Spaltennamen (Attributwert von
Sensor) auf Vorhandensein abgefragt. Wird ein Spaltenname gefunden, der sich noch
nicht in <Tab_Name> befindet, werden diese Spalten, wie vorher beschrieben, in die
Datentabellen eingefügt.
Bemerkung:
Eine Schwäche dieser Vorgehensweise ist, dass nur die Tabelle <Tab_Name> abgefragt
wird. Der Fall eines Systemabsturzes, nachdem die Spalte in <Tab_Name> eingetragen
wurde, aber noch nicht oder nur teilweise in die Datentabellen, würde ein automatisches
Nachtragen durch erneuten Start des Skriptes unmöglich machen. Die Spalten müssten
dann von Hand nachgetragen werden.
4.3 Ändern von ZUORDNUNG
Die Änderung von ZUORDNUNG ist, wie in den vorherigen Kapiteln ausführlich
beschrieben, eine sehr sensible Angelegenheit. Hier soll kurz noch einmal zusammengefasst werden, was beim Ändern beachtet werden muss.
4.3.1 Hinzufügen von Zeilen
Das Hinzufügen von Zeilen in ZUORDNUNG, nach dem Anlegen der Datenbank (Kap.
4.1.3), sollte nur unter der Eingabemaske in Forms (Kap. 5) geschehen. Dort werden die
9
Für Binärwerte werden eigentlich nur die 0 und die 1 benötigt. Die Binärwerte werden aber eventuell im
Messintervall von 6 min. integriert. Das würde realisiert, um z.B. Prozentual die Öffnungszeiten eines
Fensterkontaktes in diesem Zeitraum zu erfassen.
44
Realisierung
notwendigen Sicherheitsprüfungen durchgeführt. Allerdings sollte der Administrator
sicher sein, dass seine Angaben stimmen; sind die Änderungen einmal akzeptiert,
können sie ohne weiteres nicht mehr rückgängig gemacht werden.
4.3.2 Löschen von Zeilen
Das Löschen von Zeilen aus ZUORDNUNG ist prinzipiell verboten, da es dann Spalten
in Datentabellen gibt, auf die nicht mehr verwiesen wird. Weiter könnten keine Tabellen
mehr geändert werden, da die Fehlerprüfung in ZUB_TMP_DATEN immer eine Spalte
findet, die nicht in ZUORDNUNG steht (Fehler Bit 3 -> Schritt 3 Kap. 4.2.2).
Sollte ein Sensor im Gebäude selbst demontiert und nie wieder gebraucht werden,
liefert er natürlich keine Messwerte mehr. Die automatische Fehlerkontrolle würde
diesen fehlenden Messwert immer mit Fehler 2 quittieren und in den Tabellen
<Tab_Name>_FEHL_AUTO_TAB eintragen. Die automatische Fehlerkontrolle benötigt relativ viel Rechenzeit. Daher sollte es möglich sein, eine Zeile aus ZUORDNUNG
zu entfernen. Es gibt für einen solchen Fall keine Eingabemaske oder Hilfestellung.
Diese Änderungen müssen von Hand durchgeführt werden. Folgende Schritte müssen
durchgeführt werden.
1. Löschen
der
Zeile
aus
ZUORDNUNG.
Diese Zeile darf nie wieder verwendet werden. Der Attributwert von Sensor und
gleichzeitig R_Nr darf für diesen <Tab_Name> nie wieder verwendet werden,
da sonst Daten unter die gleiche Spalte mit gleicher Raumnummer geschrieben
werden, die vorher einem anderen Sensor zugeordnet waren. Es entsteht eine
Inkonsistenz. Diese Änderungen müssen dokumentiert werden und ab diesem
Zeitpunkt muss jede Änderung in ZUORDNUNG mit dieser Dokumentation
verglichen werden.
2. Löschen
der
Tabelle
ZUB_DATEN_TMP_TAB.
Diese Tabelle kann gelöscht werden, da sie täglich neu gefüllt wird. Allerdings
muss die Firma benachrichtigt werden, welche die Leittechnik im ZUB betreut,
damit das Füllen der Tabelle weiter funktioniert.
3. Anlegen der Tabelle ZUB_DATEN_TMP_TAB mit Datum, Uhrzeit als
Attributen, wie es in den Umgebungstabellen schon einmal geschehen ist (Kap.
4.1.3).
45
Realisierung
4. Starten des Skriptes " Ablaufstrg_DB_Tabellen_anlegen.sql" (Kap. 4.2).
Hier werden die Spalten in ZUB_DATEN_TMP_TAB eingefügt.
4.3.3 Ändern von Zeilen
Das Ändern von Zeilen in ZUORDNUNG ist nur soweit erlaubt, als dass man den
Messbereich ändert. Dieser wird von der automatischen Fehlerprüfung verwendet. Die
Änderung des Messbereichs geschieht unter der Eingabemaske (Kap. 5). Wird der
Messbereich geändert, werden alle Daten, für die der Messbereich geändert wurde,
erneut geprüft und zwar vom ersten Tag an.
Führt man die Änderung des Messbereichs nicht unter der Eingabemaske durch, werden
nur Daten ab der Änderung geprüft.
Ändert man die Hw_Adr und ist diese noch nicht vorhanden, wird eine neue Spalte in
ZUB_TMP_DATEN angelegt und die Daten in die Spalte R_Nr und Sensor eingetragen, auf die vorher eine andere Hw_Adr verwiesen hat. Die Datenintegrität ist
verletzt. Genauso verhält es sich mit Änderungen des Sensors und der Raumnummer bei
gleichbleibender Hw_Adr.
Es kann vorkommen, dass beim Anlegen der Datenbank Fehler gemacht wurden, indem
Verweise durcheinander gebracht wurden. Es gibt eine Option bei der Forms-Eingabemaske Änderungen vorzunehmen (Kap. 5). Diese sollten aber in den ersten 14 Wochen
vorgenommen werden. Solange sind in ZUB_DATEN_TMP_TAB die ersten Messdaten vorhanden; es entstehen keine Datenverluste. Man sollte nach dem Ändern die
Datentabellen leeren ("...\Test\DB_Tabellen_leeren.sql") oder besser die Datentabellen
löschen
("DB_Tabellen_loeschen.sql")
und
neu
anlegen
("Ablaufstrg_DB_Tabellen_anlegen.sql").
4.4 Ausführen der Datenbank
Hier soll das Augenmerk auf die Datenintegrität gelegt werden, da bisher hauptsächlich
über das Anlegen und Ändern von Tabellen gesprochen wurde. Die Frage lautet hier,
wie das Eintragen der Daten realisiert wird.
46
Realisierung
4.4.1 Tägliche Ablaufsteuerung (Ablaufstrg_taeglich.sql)
Die tägliche Ablaufsteuerung wird einmal am Tag, nachdem die Daten in ZUB_DATEN_TMP_TAB aktualisiert wurden, ausgeführt. Abbildung 6 (Kap. 3.3.1) zeigt, was
bei dieser Verarbeitung geschieht. Unter Abbildung 14 ist das skripttechnisch dargestellt. Das Verbessern fehlerhafter Datumseinträge und die automatische Fehlerkontrolle
wurden schon ausführlich in Kap. 3.3.1 behandelt.
Zeittab.sql
ASCII-Datei im Verzeichnis
“Meldungen” mit Informationen
aus den Skripten und Prozeduren
Ablaufstrg_taeglich.txt
datum_verbessern
Gespoolte Datei
Rohdaten_eintragen.sql aus
Spool_Rohdaten_eintragen.sql
Fehler_eintragen.sql
Aktualisiert ZEITTAB mit
den Referenzzeiten
Prozedur zum Verbessern der
ungenauen Datumseinträge
in ZUB_DATEN_TMP_TAB
Übernahme der Messdaten aus
ZUB_DATEN_TMP_TAB in die
Messdatentabellen
<Tab_Name>_TMP_TAB und
<Tab_Name>_ROH_TAB
Eintragen der Fehler in die automatischen Fehlertabellen
<Tab_Name>_FEHL_AUTO_TAB
Ende
Abbildung 14: Täglicher Ablauf (Ablaufstrg_taeglich.sql)
Für die Sicherung der Messdaten in die Rohdatentabellen <Tab_Name>_ROH_TAB ist
ZUORDNUNG grundlegend. Ist die Integrität von ZUORDNUNG gewährleistet, sind
alle Spalten aus ZUB_DATEN_TMP_TAB bekannt, die in eine Spalte von
<Tab_Name>_TMP_TAB mit einer bestimmten Raumnummer R_Nr eingetragen
werden.
Man könnte ein PL/SQL Skript mit DBMS_SQL schreiben, welches diese Aufgabe
übernimmt. Das wäre negativ für die Laufzeit. Wesentlich schneller geht es, die Daten
in die temporären- und Rohdatentabellen mit einer reinen SQL-Datei aufzunehmen.
Programmtechnisch wird das gelöst, indem die Datei "gespoolt" wird. Oracle bietet das
Spooling normalerweise an, um Meldungen in einer ASCII Datei zu speichern oder um
Tabellen dort als ASCII –Code abzulegen, damit die Daten von Auswertprogrammen
47
Realisierung
(wie z.B. Matlab/Simulink) gelesen werden können (einige Programme greifen direkt
über ODBC auf die Tabellen zu). Hier wird das Spoolen genutzt werden, um die
Integrität der Datenbank zu sichern und den Ablauf zu automatisieren. Es muss die
Änderung von ZUORDNUNG reichen, um die Daten richtig abzulegen. Es ist sehr
fehlerträchtig, wenn Änderungen an vielen Stellen vorgenommen werden müssen.
Das Spoolen dieser Datei findet jedes Mal statt, wenn ZUORDNUNG geändert und das
Skript "Ablaufstrg_DB_Tabellen_anlegen.sql" gestartet wurde. Dieser Prozess funktioniert nur, wenn eben genanntes Skript erfolgreich ausgeführt wurde. Das ist immer in
der Datei '...\Meldungen\Datenbanktabellen.txt" erkenntlich.
Um das Beispiel aus Kap. 3.2.4 "Die Tabellen ZUORDNUNG und ANHANG" aufzunehmen, wird hier das Ergebnis des Spoolens aus den Tabellen für MESSR (Messraum)
gezeigt. STDR (Standardraum) wurde hier gelöscht, ist aber im Original vorhanden.
- Datei erstellt am 14.12.2000 15:07
----------------------------------------------------------------------------------------- Datei: Rohdaten_eintragen.sql
-- Erstellt: 14.12.2000 15:07
-- Aus Datei SPOOL_Rohdaten_eintragen.sql
-- Beschreibung:
-- Kopieren der Daten aus ZUB_DATEN_TMP_TAB in die Datenbank TMP Tabellen
-----------------------------------------------------------------------------------------******************************************************************--- Leeren der temporären Tabellen
TRUNCATE TABLE MESSR_TMP_TAB;
COMMIT;
--******************************************************************--- Löschen ungültiger Einträge von ZUB_DATEN_TMP_TAB
DELETE FROM ZUB_DATEN_TMP_TAB WHERE Datum IS NULL OR Uhrzeit IS NULL;
COMMIT;
--******************************************************************--- Kopieren der Werte in die temporären Tabellen,
-- bei denen das Datum neuer ist als in den Rohdatentabellen.
----------------------------------------------INSERT INTO MESSR_TMP_TAB (Datum, R_Nr,
T_OBERFL0, T_OBERFL1, T_OBERFL2)
SELECT to_date(Datum||Uhrzeit,'dd.mm.yyyy hh24:mi'), '1_02',
H00112, H00113, H00114
FROM ZUB_DATEN_TMP_TAB
WHERE to_date(Datum||Uhrzeit,'dd.mm.yyyy hh24:mi') >
(SELECT nvl(max(Datum), to_date('01.01.1111','dd.mm.yyyy hh24:mi')) FROM
MESSR_ROH_TAB
WHERE R_Nr ='1_02');
COMMIT;
-----------------------------------------------
48
Realisierung
--******************************************************************--- Kopieren der Temporären Daten in die Rohdatentabellen
INSERT INTO MESSR_ROH_TAB SELECT * FROM MESSR_TMP_TAB;
COMMIT;
--******************************************************************--10
Als erstes werden ungültige Einträge aus ZUB_DATEN_TMP_TAB gelöscht. Ungültig
sind alle Daten, die kein Datum oder keine Uhrzeit enthalten. Das sollte eigentlich nicht
auftreten, wird hier jedoch zur Sicherheit ausgeführt. Der nächste Schritt ist das Leeren
der Tabellen <Tab_Name>_TMP_TAB, da die Messdaten nicht mehr aktuell sind.
Danach werden die Werte aus ZUB_DATEN_TMP_TAB in die temporären Dateien
verteilt und gesichert. Die Raumnummer wird immer berücksichtigt. Es werden nur
Daten gesichert, die neuer sind, als das letzte gültige Datum mit der entsprechenden
Raumnummer in <Tab_Name>_ROH_TAB. Befindet sich kein gültiges Datum für
diese Raumnummer in den Rohdatentabellen, werden alle Daten aus ZUB_DATEN_TMP_TAB gesichert. Sind die Daten in den Tabellen mit temporären Messdaten
eingetragen, werden sie 1:1 in die Rohdaten aufgenommen. Die folgende automatische
Fehlerkontrolle durchsucht die temporären Tabellen.
4.4.2 Füllen der Datentabellen zur Auswertung (Ablaufstrg_manuell.sql)
Das Skript " Ablaufstrg_manuell.sql" wird erst korrekt ausgeführt, nachdem
"Fuelle_Fehl_inv_Tab.sql" ausgeführt wurde. Genaueres zu beiden findet sich in Kap.
3.3.2 "Manueller Ablauf mit Blick auf die Tabelle FEHL_TAB" und in Kap. 5.5.
Hier gilt für die Datenintegrität dasselbe wie im vorherigen Kapitel. Beim Starten von
"Ablaufstrg_manuell.sql" werden zwei Dateien gespoolt. Eine zum Füllen der korrigierten Rohdatentabellen und eine andere zur Berechnung der Mittelwerte (Abbildung 15)
10
Bei der Zeichenfolge – handelt es sich um ein Kommentar.
49
Realisierung
Fuelle_Fehl_inv_Tab.txt
Fuelle_Fehl_inv_Tab.sql
Spool_Rohkorr.sql
ASCII-Datei im Verzeichnis
“Meldungen” mit Informationen
aus den Skripten und Prozeduren
Spool_TagMonatJahr.sql
Rohkorr.sql
Ablaufstrg_manuell.txt
TagMonatJahr.sql
Füllen der inversen Fehlertabellen.
Wird extra unter der Eingabemaske
in Forms gestartet.
Erzeugen der SQL Datei Rohkorr.sql
zur Berechnung der korrigierten Rohdaten und zum Eintrag in
<Tab_Name>_ROHKORR_TAB.
Erzeugen der SQL Datei
TagMonatJahr.sql zur Berechnung der
Tages-, Monats- und Jahresmittelwerte
Füllen von
<Tab_Name>_ROHKORR_TAB
durch multiplizieren von
<Tab_Name>_ROH_TAB mit
<Tab_Name>_FEHL_INV_TAB
Füllen von
<Tab_Name>_TAG_TAB,
<Tab_Name>_MONAT_TAB und
<Tab_Name>_JAHR_TAB
Ende
Abbildung 15: Manueller Ablauf (Ablaufstrg_manuell.sql)
Zuerst werden alle Tabellen, die Messdaten – auch Mittelwerte – enthalten, geleert. Nur
die inversen Fehlertabellen bleiben gefüllt. Wie oben bereits erwähnt, werden die korrigierten Rohdaten gefüllt, indem die Rohdatentabellen mit den inversen Fehlertabellen
multipliziert werden. Das sei wieder am Beispiel des Messraumes MESSR gezeigt:
--------------------------------------------------------------------------------- Datei: ROHKORR.SQL
-- Erstellt: 22.12.2000 17:02
-- Aus Datei SPOOL_ROHKORR.SQL
-- Beschreibung:
-- Füllen der Tabellen ..._ROHKORR_TAB:
-- ..._ROHKORR_TAB wird durch Multiplikation der Tabellen ..._ROH_TAB und
-- ..._FEHL_INV_TAB gefüllt.
---------------------------------------------------------------------------------******************************************************************--- Leeren der Tabellen ..._ROHKORR_TAB
TRUNCATE TABLE MESSR_ROHKORR_TAB;
COMMIT;
--******************************************************************--- Füllen der Tabellen ..._ROHKORR_TAB
----------------------------------------------INSERT INTO MESSR_ROHKORR_TAB (Datum, R_Nr,
T_OBERFL0, T_OBERFL1, T_OBERFL2)
SELECT r.Datum ,r.R_Nr ,
50
Realisierung
f.T_OBERFL0 * r.T_OBERFL0, f.T_OBERFL1 * r.T_OBERFL1, f.T_OBERFL2 *
r.T_OBERFL2
FROM MESSR_ROH_TAB r, MESSR_FEHL_INV_TAB f
WHERE r.Datum = f.Datum
AND r.R_Nr = f.R_Nr;
COMMIT;
-----------------------------------------------
Danach folgt die Mittelwertbildung aus den korrigierten Rohdaten für die Tageswerttabellen. Aus diesen werden die Mittelwerte für die Monatstabellen und aus diesen
wiederum die Jahrestabellen gefüllt. Hier endet das Skript.
51
Bearbeitung der DB unter Oracle Forms
5 Bearbeitung der DB unter Oracle Forms
Die Administration und Ausführung der Datenbank erfolgt hauptsächlich – bis auf die
tägliche Ablaufsteuerung – unter Oracle Forms. Forms ist eine objektorientiertes
Designprogramm- ähnlich wie Visual C++ von Microsoft oder Delphi – mit dem
Schwerpunkt Datenbankzugriffe und wird mit dem Paket Developer 2000 geliefert.
Die Administrationsoberfläche (Abbildung 16) besteht aus einer Symbolleiste (links)
und aus einem vierseitigen Register (rechts):
1. Fehler-Tabellen eintragen
2. ZUORDNUNG bearbeiten
3. Messbereich ändern
4. Fehlertabelle bearbeiten
In diesem Kapitel wird beschrieben, welche Änderungen und Einträge welche Auswirkungen haben und wie diese am besten vorgenommen werden. Als erstes werden die
Registerseiten behandelt, da die Einträge sich auf die Handhabung der Symbolleiste
auswirken.
Die Registerseiten hängen in ihren Auswirkungen untereinander zusammen. Die Änderungen werden auf den Registerseiten bis zur endgültigen Übernahme zwischengespeichert. Solange Änderungen geplant sind –aber noch nicht übernommen-, werden die
übrigen Registerseiten – bis auf "Fehlertabelle bearbeiten" – inaktiv geschaltet. Das
Bearbeiten dieser ist erst nach dem Verwerfen oder Übernehmen möglich.
Änderungen werden zumeist nicht gleich ausgeführt, da sie sensible Auswirkungen auf
die Datenbank haben.
5.1 Fehlertabellen bearbeiten
In Abbildung 16 ist die Tabelle FEHL_TAB , u.a. mit den Einträgen aus FEHL_AUTO_ANZEIGE_TAB gefüllt, dargestellt (Kap. 3.2.5.2). Ausgehend von dem dortigen
Beispiel sieht man oben die "Zusammenfassung der automatischen Fehlererkennung".
Hier handelt es sich um die Ansicht der Tabelle FEHL_AUTO_ANZEIGE_TAB, die
aus den automatischen Fehlertabellen <Tab_Name>_FEHL_AUTO_TAB gefüllt
wurde. Dabei werden nur Einträge berücksichtigt, die noch nicht mit dem Eintrag
52
Bearbeitung der DB unter Oracle Forms
Check_Flag und Bearbeiter als geprüft markiert wurden. Die Spalten Tab_Name
(entspricht <Tab_Name>), Sensor, R_Nr , Fehlerkennung (Fehlernummer aus FEHLER_CODE), Anfangsdatum, Enddatum und Anzahl können nicht bearbeitet werden.
Sie wurden automatisch erkannt.
Checked und Bearbeiter müssen dagegen bearbeitet werden. Nach Anklicken des
Kontrollkästchens Checked muss ein Bearbeiter eingegeben werden (das Programm
lässt keine andere Aktion zu).
Ganz unten ist die Tabelle FEHL_TAB zu erkennen, in der alle gefundenen Fehler von
Hand eingetragen werden (Kap. 3.2.5.2). Die Eingabemaske befindet sich darüber.
Abbildung 16: Register: Fehlertabelle bearbeiten
Zurück zur "Zusammenfassung der automatischen Fehlererkennung". Checked wird
markiert, wenn der Administrator diesen Fehler in den automatischen Fehlertabellen
<Tab_Name>_FEHL_AUTO_TAB gesichtet und mit den Rohdaten verglichen hat.
53
Bearbeitung der DB unter Oracle Forms
Erkennt er den Fehler als realen Fehler an, übernimmt er ihn in FEHL_TAB und
markiert ihn. Sieht der Administrator, dass es sich nicht um einen Fehler handelt, wird
Checked gesetzt, aber der Wert nicht in FEHL_TAB übernommen.
Beim Drücken von "Neu Füllen" werden alle automatischen Fehlertabellen erneut
durchsucht und die Einträge gefunden, die automatisch fehlerhaft markiert wurden und
als ungeprüft gelten (Check_Flag ist NULL). Alle Änderungen, die nicht mit "Ok"
übernommen wurden, gehen dabei verloren, da FEHL_AUTO_ANZEIGE_TAB geleert
und wieder neu gefüllt wird (Skript "...\FORMS\fehl_auto_anzeige.sql").
Beim Drücken von "Ok" beginnt die Aktualisierung der automatischen Fehlertabellen.
Alle Fehler mit dem Haken Checked werden in den automatischen Fehlertabellen mit
einer 1 in der Spalte Check_Flag und dem eingetragenen Bearbeiter in der Spalte Bearbeiter aktualisiert (Skript "...\FORMS\fehl_auto_markierung.sql"). Danach wird die
Tabelle FEHL_AUTO_ANZEIGE_TAB neu gefüllt (Skript "...\FORMS\ fehl_auto_anzeige.sql"). Dieser Prozess kann bei vielen Fehlern einige Zeit dauern. Erst sollten
einige Fehler überprüft und übernommen werden, bevor einer der beiden Knöpfe
bedient wird.
Ein Problem der automatischen Fehlertabellen besteht, wenn bei verschiedenen Sensoren Fehler zur selben Zeit in den selben Räumen auftreten. Es gibt schließlich nur eine
Spalte für Checked und den Bearbeiter. Würde man nur einen Fehler überprüfen und
diesen in den automatischen Fehlertabellen markieren, würde der andere – der zur
selben Zeit im selben Raum auftritt - nicht mehr nach dem erneuten Füllen von
FEHL_AUTO_ANZEIGE_TAB erscheinen, da Checked für diesen Raum und dieses
Datum gesetzt ist . Es wird eine Funktion aufgerufen, die diese möglichen Überschneidungen in FEHL_AUTO_ANZEIGE_TAB findet, bevor die automatischen Fehlertabellen markiert werden. Sie prüft,ob ein anderer oder mehrere, die zur selben Zeit im
selben Raum auftreten, nur teilweise in FEHL_AUTO_ANZEIGE_TAB markiert
wurden. In diesem Fall wird das Fenster "Mögliche zusammenhängende Fehler"
geöffnet (Abbildung 17). Es handelt sich hierbei um eine reine Ansicht. Die Fehler
müssen weiterhin im Register markiert werden. Auf dem aktuellen Fenster gibt es
einige Knöpfe. Diese sind in der Abbildung beschrieben. Normalerweise sollte "Weitere
markieren" bedient und die Liste abgearbeitet werden. Nach Abarbeiten der Liste und
erneutem Drücken von "Ok" auf der Registerseite, wird die Markierung durchgeführt.
54
Bearbeitung der DB unter Oracle Forms
Abbildung 17: Fenster: Mögliche Überschneidungen
Die Eingabemaske für FEHL_TAB (Abbildung 16 Mitte) wird einerseits mit den
Fehlern aus FEHL_AUTO_ANZEIGE_TAB gefüllt, andererseits mit gefundenen
Fehlern beim Sichten der Rohdaten.
Eine Erleichterung beim Füllen der Maske, bietet ein Mausklick auf Tab_Name bei
"Zusammenfassung der automatischen Fehlererkennung". Die Maske wird mit der
angeklickten Zeile gefüllt.
Jeder Eintrag enthält eine laufende Nummer (Lfd. Nr.), die automatisch angezeigt und
nicht geändert werden kann. Sie ist immer um eins größer, als die maximale Nummer.
Wird eine laufende Nummer durch "Löschen", die kleiner ist als die Maximale, entfernt,
wird sie nicht mehr neu eingefügt. Das soll dem Administrator sagen, dass es mal einen
Eintrag gab, der jetzt nicht mehr gültig ist. Die Tabelle FEHL_TAB sollte vor einer
Änderung immer ausgedruckt und archiviert werden, damit man den Verlauf verfolgen
kann (mehr dazu in Kap. 5.5 Knopf "Spool").
Bevor die Maske in FEHL_TAB durch Drücken von "Übernehmen" eingefügt wird,
wird die Maske auf Syntax geprüft. Die Angaben der Tabelle, des Sensors und der
55
Bearbeitung der DB unter Oracle Forms
Raumnummer sind T-Listen bzw. Pull-Down-Menues. Sie enthalten Namen von Tabellen, Sensoren und Räumen, die in ZUORDNUNG vorkommen. Spalte und R_Nr. enthalten zusätzlich die Auswahl "ALLE". Es kann vorkommen, dass alle Sensoren in
einem Raum fehlerhaft sind oder dass ein bestimmter Sensor in allen Räumen falsch
misst oder dass alle Sensoren in allen Räumen fehlerbehaftet sind. Letzteres kommt bei
einem Ausfall der Leittechnik vor.
Syntaktisch kann bei diesen T-Listen kein Fehler entstehen. Die Fehlerkennung ist die
Nummer aus der Tabelle FEHLER_CODE, die dem Fehler zugeordnet ist (Kap. 3.2.5.2
und Kap. 5.4). Sie darf zwischen 1-99 liegen. Das Anfangs- und Enddatum muss im
Oracle Format 'dd.mm.yyyy hh24:mi' vorliegen (z.B. 24.12.2001 23:55). Das Anfangsdatum darf nicht leer sein. Das Enddatum darf leer sein, wenn ein Fehler aufgetreten ist,
aber der Zeitpunkt der Reparatur ungewiss ist (Kap. 3.3.2). Der Bearbeiter muss immer
bekannt sein und muss daher eingegeben werden. Eine Bemerkung ist wichtig, aber
nicht notwendig.
Weitere Knöpfe, die für die Registerseite von Bedeutung sind, sind "Spool" und
"FEHL_TAB verarbeiten" auf der Symbolleiste (Kap. 5.5)
5.2 ZUORDNUNG bearbeiten
In Abbildung 18 ist die Eingabemaske zur Bearbeitung von ZUORDNUNG zu sehen.
Oben befindet sich die Eingabemaske selbst. Darunter sind die Änderungen angezeigt,
die durch Drücken von "Hinzufügen/Bearbeiten" eingetragen wurden.
Die Richtlinien zum Löschen, Hinzufügen und Ändern von ZUORDNUNG sind in
Kapitel 4.3 "Ändern von ZUORDNUNG" festgehalten und sollten unbedingt beachtet
werden.
Die Eingabemaske wird auf syntaktische Mängel geprüft, bevor sie in die "Änderungen
von ZUORDNUNG" aufgenommen wird. Zum einen dürfen in die Felder Hw_Adr,
R_Nr, Sensor, Tab_Name nur die Zeichen 0-9, A-Z und ein Unterstrich "_" eingetragen
werden. Kleingeschriebenes wird automatisch durch Großbuchstaben ersetzt. Das
erleichtert bei einer Auswertung die Selektion, da der Administrator weiß, es kommen
nur Großbuchstaben vor. Die Felder Minwert und Maxwert dürfen nur Zahlen im
Wertebereich von –999.99 bis 999.99 enthalten.
56
Bearbeitung der DB unter Oracle Forms
Abbildung 18: Register: ZUORDNUNG bearbeiten
Zur Sicherheit wird - falls die Hw_Adr schon in ZUORDNUNG steht - ein Fenster
angezeigt (Abbildung 19). Hier wird dem Administrator verdeutlicht, dass es schon
einen Verweis aus ZUB_DATEN_TMP_TAB auf die Datentabellen gibt und er diesen
durch einen neuen ersetzt, wenn er "Zeile ersetzen" drückt. "Schließen" zeigt wieder die
gewohnte Registerseite an, ohne dass Änderungen übernommen werden.
57
Bearbeitung der DB unter Oracle Forms
Abbildung 19: Zeilen in ZUORDNUNG ersetzen
Die "Änderungen in ZUORDNUNG" in Abbildung 18 können komplett verworfen oder
übernommen werden.
Falls neue Datentabellen angelegt werden müssen, erscheint ein neues Fenster, damit
der Administrator auch hier noch einmal prüfen kann, ob er wirklich neue Datentabellen
anlegen will oder ob er sich verschrieben hat (Abbildung 20). Die übrigen Punkte, die in
den vorhandenen Datentabellen hinzugefügt oder geändert werden, werden in jedem
Falle nach dem Bedienen von "Übernehmen" in ZUORDNUNG eingetragen.
Abbildung 20: Fenster: Erstellen einer Tabelle
58
Bearbeitung der DB unter Oracle Forms
Die Grundlage dieser Registerseite bildet das Skript "Ablaufstrg_DB_Tabellen_anlegen.sql", welches ausführlich in Kap. 4.2.3 "" beschrieben wurde. Nachdem die Änderungen ausgeführt wurden, wird automatisch der Standardeditor Notepad gestartet und
die Textdatei ...\Meldungen\Datenbanktabellen.txt angezeigt. Der Administrator sieht
direkt, ob die Änderungen erfolgreich durchgeführt wurden.
5.3 Messbereich ändern
Die Änderung des Messbereiches wirkt sich auf <Tab_Name>_FEHL_AUTO_TAB
aus. In Abbildung 21 ist die Tabelle ZUORDNUNG abgebildet. In dieser können nur
die Felder Minwert und Maxwert des Messbereiches bearbeitet werden. Nach der
Änderung des Messbereiches werden die geänderten Werte in das Feld unterhalb der
Tabellenansicht angezeigt.
Wieder besteht die Option des Verwerfens oder Übernehmens. Im ersten Fall wird die
Tabelle in ihren ursprünglichen Zustand zurückgesetzt, im zweiten Fall wird der Messbereich der geänderten Werte neu geprüft.
Alle Werte in <Tab_Name>_FEHL_AUTO_TAB, die in der referierten Spalte "Sensor"
stehen und den Fehler 3 aus FEHLER_CODE enthalten, werden auf NULL zurückgesetzt. Jetzt wird die entsprechende Spalte in <Tab_Name>_ROH_TAB auf den neuen
Messbereich überprüft und die Werte in die automatische Fehlertabelle eingetragen.
Wieviele Änderungen vorgenommen wurden und welche Befehle ausgeführt wurden, ist
ganz unten in der Tabelle zu erkennen.
59
Bearbeitung der DB unter Oracle Forms
Abbildung 21: Register: Messbereich ändern
Die Messbereichsänderungen wirken sich auf die Tabelle FEHL_AUTO_ANZEIGE_TAB aus, da mit dem Löschen des alten Messbereiches auch die Prüfflags
Checked und der Bearbeiter aus den automatischen Fehlertabellen gelöscht werden
müssen (nur bei Fehler 3 in FEHLER_CODE)11. Im Register "Fehlertabellen eintragen"
sollte daher der Knopf "Neu füllen" angewendet werden.
5.4 Fehlertabelle bearbeiten
Abbildung 22 zeigt die Tabelle FEHLER_CODE an. Standardfehler der automatischen
Fehlererkennung sind in den Nummern 1-3 festgelegt. Diese können nicht geändert
werden. Der Administrator soll diese Tabelle nutzen, um gesichtete Fehler aus den
11
Programmiertechnisch in DBMS_SQL nur aufwendig zu lösen. Es müssten mehrere FULL TABLE
SCANS durchgeführt werden, die sehr rechenzeitintensiv sind.
60
Bearbeitung der DB unter Oracle Forms
Datentabellen, die mit der Fehlernummer in FEHL_TAB eingetragen werden, zu
beschreiben.
Abbildung 22: Register: FEHLER_CODE bearbeiten
"Fehler Bearbeiten" öffnet die Eingabemaske in Abbildung 23. Die Beschreibung kann
jederzeit eingetragen oder geändert werden; allerdings sollten einmal festgelegte
Beschreibungen nicht mehr geändert werden, damit FEHL_TAB konsistent bleibt.
Abbildung 23: Fenster: Fehler eintragen
61
Bearbeitung der DB unter Oracle Forms
5.5 Die Symbolleiste
Die Symbolleiste aus Abbildung 24 startet verschiedene Skripte.
Abbildung 24: Symbolleiste
Sie enthält folgende Knöpfe:
1. "ZUB
DB
Ausführen"
Startet das Skript "Ablaufstrg_manuell.sql" (Kap. 3.3.2). Zeigt automatisch die
Ergebnisse
in
"...\Meldungen\Ablaufsteuerung_manuell.txt"
an.
Sollten die inversen Fehlertabellen noch nicht gefüllt sein, werden keine Daten
übernommen. Falls neue Messdaten seit dem letzten Füllen der Fehlertabellen
62
Bearbeitung der DB unter Oracle Forms
aufgelaufen sind, muss "FEHL_TAB verarbeiten" (s.u.) erneut ausgeführt werden, da sich sonst nicht alle Datumseinträge und Raumnummern in den inversen
Fehlertabellen befinden.
2. "FEHL_TAB
verarbeiten"
Füllen der inversen Fehlertabellen <Tab_Name>_FEHL_INV_TAB aus der
Tabelle FEHL_TAB. Dieser Vorgang ist unabhängig von der manuellen Ablaufsteuerung, damit die inversen Fehlertabellen nicht immer wieder neu gefüllt
werden müssen, falls keine neuen Messdaten angefallen sind oder diese im
Moment nicht interessieren. Genaueres hierzu befindet sich in den Kapiteln
3.3.2 "Manueller Ablauf mit Blick auf die Tabelle FEHL_TAB"
3. "Spool"
Spoolen wurde im Kap. 4.4.1 beschrieben. Das aufgerufenen Skript "...\Forms\
spool_fehler_tabs.sql" schreibt den Inhalt der Tabellen FEHL_TAB, FEHL_AUTO_ANZEIGE_TAB, MOEGLICHE_UEBERSCHNEIDUNG_TAB in die
Datei "...\Meldungen\Fehler_Tabs.txt". Vor der Bearbeitung der Fehlertabellen
sollte die Funktion ausgeführt werden. Die Textdatei wird automatisch angezeigt
und sollte ausgedruckt und archiviert werden, damit der Änderungsstand immer
bekannt ist.
4. "ZUB
täglicher
Ablauf"
Starten der Skriptes "Ablaufstrg_taeglich.sql" (Kap. 3.3.1und Kap. 4.4.1). Die
tägliche Ablaufsteuerung wird – wie beschrieben – jeden Tag gestartet. Dieser
Knopf führt die gleiche Funktion aus. Die Ergebnisse werden in "...\Meldungen\
Ablaufsteuerung_taeglich.txt " automatisch angezeigt. Bevor dieser Knopf
bedient wird, sollte der Administrator die Textdatei öffnen und Einsicht nehmen,
ob wichtige Meldungen in ihr sind, bevor sie nach Bedienen des Knopfes neu
angelegt wird.
5. EXIT
Verlassen der Anwendung ohne Änderungen zu speichern oder zu übernehmen.
Es wird vor dem Verlassen auf etwaige Änderungen geprüft, die noch nicht
übernommen oder verworfen wurden.
63
Zusammenfassung und Ausblick
6 Zusammenfassung und Ausblick
6.1 Zusammenfassung
In dieser Arbeit wurde eine Datenbank zur Messwertarchivierung beschrieben. Die
Messwerte werden im "Zentrum für umweltbewusstes Bauen" (ZUB) aufgenommen,
der Datenbank als Rohdaten übergeben und weiter verarbeitet. Die von der Leittechnik
erfassten Messwerte werden großteils für die Gebäudesteuerung benutzt. Das Konzept
der Datenbank beruht auf der Tatsache, dass die archivierten Daten später ausgewertet
werden. Die Auswertung soll zu Verbesserungen bei der Steuerung der Haustechnik
führen.
Die ZUB-Leittechnik wird in Informationsschwerpunkte – wie z.B. Standardräume oder
Messräume – eingeteilt. Die Informationsschwerpunkte geben an, welche Werte gemessen werden (Kap. 3.1.1 - 3.1.3).
Alle Messwerte werden von der Leittechnik täglich in ZUB_DATEN_TMP_TAB
geschrieben. Sie enthält die Messwerte der letzten 14 Wochen. Als Spaltennamen
werden die von der Leittechnik zugewiesenen Hardwareadressen benutzt (Kap. 3.1.4).
Alle Messdaten werden in den sogenannten Rohdatentabellen gesammelt (Kap. 3.2.1).
Für eine Auswertung müssen die rohen Daten der Datenbank aufbereitet werden. Das
geschieht durch eine automatische Fehlererkennung und durch eine ergänzende manuelle Fehlererkennung, bei der der Administrator die Messdaten sichtet (Kap. 3.2.2).
Daraus ergeben sich die notwendigen Datentabellen. Es sind die Rohdatentabellen,
Fehlertabellen, korrigierten Rohdatentabellen und Mittelwerttabellen. Letztere sind
wiederum in Tages-, Monats- und Jahresmittelwerttabellen aufgeteilt (Kap. 3.2).
Hinsichtlich einer späteren Auswertung sind Hardwareadressen als Spaltennamen in der
Tabelle ZUB_DATEN_TMP_TAB ungeeignet (s.o.) (Kap. 3.1.6). Für eine Auswertung
und die Übersichtlichkeit ist es besser, die physikalische Eigenschaft des Messsensors
als Spaltennamen zu wählen und den Ort der Messung zu kennen. Dazu werden die
Daten in den Datentabellen neu angeordnet. Die Datentabellen enthalten also die physikalische Eigenschaft des Sensors als Spaltennamen und zusätzlich eine Spalte mit der
Raumnummer (R_Nr) im ZUB als Bestimmung des Ortes. Der Anwender weiß sofort,
wann, was und wo gemessen wurde.
64
Zusammenfassung und Ausblick
Es muss sicher gestellt sein, dass bei dem neuen Anordnen die Daten den richtigen
Spalten zugeordnet werden. Die Verbindung zwischen ZUB_DATEN_TMP_TAB und
den Datentabellen mit dem Ort (Raumnummer) und der physikalischen Eigenschaft ist
die Tabelle ZUORDNUNG (Kap. 3.2.4).
Die Verknüpfung in ZUORDNUNG genügt nur dann der Anforderung nach Datenkonsistenz, wenn die Datentabellen automatisch angelegt und geändert werden können
(Kap. 4.2). Um alle Datentabellen automatisch zu erstellen, benötigt man Tab_Name in
ZUORDNUNG und Anhang aus der Tabelle ANHANG. ANHANG enthält Einträge
wie _ROH_TAB, _ROHKORR_TAB oder _JAHR_TAB. Setzt man Tab_Name mit den
Einträgen aus ANHANG zusammen, erhält man die vollständigen Namen der Datentabellen und kennt ihren Inhalt. Die Spaltennamen in den Tabellen sind identisch. Es
handelt sich um Abbildungen. Eine Ausnahme bilden die automatischen Fehlertabellen
und die inversen Fehlertabellen (Kap. 3.2.4).
Wie der Name "automatische Fehlertabelle" sagt, wird diese automatisch gefüllt. Es gibt
standardmäßig drei verschiedene Fehler, die in die Tabellen eingetragen werden. Erstens wird kontrolliert, ob alle Datumseinträge vorhanden, zweitens ob alle Messwerte
vorhanden sind und drittens, ob der Messwert im Messbereich liegt (Kap. 3.3.1.3).
Dadurch wird eine erste Plausibilisierung der Messdaten vorgenommen. Damit der
Administrator schnell eine Übersicht über die gefundenen Fehler bekommt, werden
diese in der Tabelle FEHL_AUTO_ANZEIGE_TAB zusammengefasst (Kap. 3.2.5.2,
5.1). Mit den Einträgen kann er nun die Rohdaten sichten und festlegen, ob es sich um
einen tatsächlichen Fehler handelt oder ob die automatische Fehlersuche falsch eingestellt ist (z.B. Messbereich nicht richtig eingegeben).
Handelt es sich um einen realen Fehler, so übernimmt der Administrator den Eintrag
aus FEHL_AUTO_ANZEIGE_TAB in FEHL_TAB. FEHL_TAB enthält alle bestätigten Fehler aus der automatischen Fehlersuche, sowie Fehler, die beim Sichten der
Rohdaten gefunden worden. Aus FEHL_TAB werden die sogenannten inversen Fehlertabellen gefüllt (Kap. 3.2.5.2 , 3.3.2 , 5.1).
Die inversen Fehlertabellen beinhalten alle Datumseinträge und Raumnummern der
Rohdaten und je nach fehlerbehaftetem oder korrektem Wert eine NULL (nichts) oder
eine 1. Durch Multiplikation der Rohdaten mit den inversen Fehlertabellen bleiben nur
als korrekt empfundene Werte übrig. Man erhält korrigierte Rohdaten, aus denen
65
Zusammenfassung und Ausblick
Mittelwerte gebildet werden. Erst wenn die Rohdaten korrigiert wurden, können sie
plausibel ausgewertet werden (Kap. 3.3.2).
Die obigen Ausführungen geben auch den gesamten Ablauf der Datenverarbeitung vor.
Dieser wird in einen täglichen Ablauf (Kap. 3.3.1, 4.4.1) und einen manuellen Ablauf
(Kap. 3.3.2, 4.4.2) unterteilt.
Täglich müssen die in ZUB_DATEN_TMP_TAB angefallenen Daten in den Rohdatentabellen gesammelt werden. Die automatische Fehlerprüfung wird auch täglich
durchgeführt. Das hat den Vorteil, dass der Administrator keine Zeit verliert, wenn er
automatisch gefundene Fehler in den Rohdaten prüft.
Die manuelle Ablaufsteuerung wird erst gestartet, wenn die inversen Fehlertabellen aus
FEHL_TAB gefüllt wurden. Daraus werden dann die korrigierte Rohdaten berechnet
und aus den korrigierten Rohdaten die Mittelwerte der Tage, Monate und Jahre.
Um die Handhabung der Datenbank zu vereinfachen, wurde unter Oracle Forms eine
Maske programmiert (Kap. 5). In dieser kann Maske können die Tabellen FEHL_AUTO_ANZEIGE_TAB und die Tabelle FEHL_TAB gefüllt werden (Kap. 5.1), ZUORDNUNG kann bearbeitet werden (Kap. 4.3, 5.2), der Messbereich der Sensoren kann
geändert werden (Kap. 5.3) und die Tabelle FEHLER_CODE (Kap. 5.4) kann erweitert
oder geändert werden. Weiter können die inversen Fehlertabellen aus FEHL_TAB
gefüllt werden und die manuelle Ablaufsteuerung gestartet werden (Kap. 5.5).
6.2 Ausblick
Das ZUB Gebäude wurde während dieser Arbeit nicht fertig gestellt. Die Leittechnik ist
nicht installiert und somit sind keine Daten angefallen. Das voraussichtliche Datenaufkommen ist sehr hoch. Die beschriebenen Funktionen wurden mit wesentlich weniger
Daten getestet. Ob dieser Test ausreichend war, kann nicht gesagt werden und wird sich
in den ersten Tagen nach Inbetriebnahme zeigen.
Ein Nachteil der Bauverzögerung ist, dass Informationen relativ langsam flossen und
Konzepte nicht fertiggestellt sind. Jedoch bieten wenige Informationen viel Platz für
Ideen und bergen Freiräume. Unter diesen Bedingungen wurde eine flexible Datenbank
erstellt, die mit kleinen Änderungen auf andere Projekte übertragbar ist. Prinzipiell
66
Zusammenfassung und Ausblick
handelt es sich um eine Verteilung und nach Bedarf eine Umbenennung von Daten aus
einer Tabelle in mehrere.
Bei der automatischen Fehlerprüfung sind Erweiterungen denkbar. Sinnvoll wäre eine
Funktion die Abweichungen der Messwerte von ihrem Mittelwert findet. In welchem
Zeitraum der Mittelwert berechnet wird und mit den Messdaten verglichen wird, muss
durch Überlegungen und Tests herausgefunden werden. Z.B. liegen Außentemperaturen
tagsüber und nachts so weit auseinander, dass die Prüfung der Abweichung vom Tagesmittelwert nicht sinnvoll erscheint. Eine weitere Fehlerprüfung wäre für Differenziale
denkbar. Man setzt hier eine maximale Abweichung vom vorherigen Messwert fest.
Z.B. ändert sich die Außentemperatur innerhalb eines 6-Minuten Intervalls wahrscheinlich nicht um 10°C.
67
Literatur
7 Literatur
[1]
Documentation Library for Oracle8 release 8.0.5
Browserbasierte Dokumentation des Programmpaketes Oracle 8.0.5
[2]
Froese, Jürgen: Effiziente Systementwicklung mit Oracle 7.1
2. Aufl., Addsison-Wesley (Deutschland) GmbH, 1995
[3]
Kemper, A.; Eickler A.: Datenbanksysteme
Wien: Oldenbourg München, 1996
[4]
Christiansen, Andreas; Höding, Michael; Rautenstrauch, Claus; Saake,
Gunter:
Oracle8 effizient einsetzen
Bonn; Reading, Massachusetts [u.a.]: Addison-Wesley-Longman, 1998
[5]
Finkenzeller, Hermann; Kracke, Ulrich; Unterstein:
Systematischer Einsatz von SQL-ORACLE
Bonn; Reading, Mass.;NewYork [u.a]: Addison-Wesley. 1989
[6]
Burleson, Donald K.: Oracle Datenbank-Anwendungen
Bonn; Albany [u.a]: Internat. Thomson Publ., 1997
[7]
Urman, Scott ORACLE (PL/SQL Programming)
New York, Berkley [u.a]: Oracle Press: Osborne McGraw-Hill 1996
[8]
SAUTER-CUMULUS GmbH, Niederlassung Frankfurt:
Informationsliste Automationseinrichtungen
Internes Papier zur Beschreibung der Messpunkte im ZUB
68
Abbildungsverzeichnis
8 Abbildungsverzeichnis
Abbildung 1: Datenverkehr über das Universitätsnetzwerk ........................................... 8
Abbildung 2: Schnittstelle zwischen Gebäudeleittechnik und ZUB-DB....................... 10
Abbildung 3: Relationsmodell..................................................................................... 14
Abbildung 4: Datentabellen und ihre Abbildungen...................................................... 15
Abbildung 5: Mind-Map der Datenbank...................................................................... 17
Abbildung 6: Täglicher und manueller Ablauf ............................................................ 25
Abbildung 7: Beispiel für den täglichen Datenfluss..................................................... 27
Abbildung 8: Verbessern ungenauer Datumseinträge in ZUB_DATEN_TMP_TAB ... 29
Abbildung 9: Automatische Fehlerkontrolle................................................................ 31
Abbildung 10: Anlegen der Datenbank ....................................................................... 36
Abbildung 11: Übersicht Ablaufsteuerung Tabellen anlegen/ändern ........................... 39
Abbildung 12: ZUORDNUNG auf mögliche Fehler prüfen......................................... 40
Abbildung 13: Ändern und Anlegen der Datentabellen (DB_Tabellen_Anlegen.sql)... 43
Abbildung 14: Täglicher Ablauf (Ablaufstrg_taeglich.sql) .......................................... 47
Abbildung 15: Manueller Ablauf (Ablaufstrg_manuell.sql)......................................... 50
Abbildung 16: Register: Fehlertabelle bearbeiten ........................................................ 53
Abbildung 17: Fenster: Mögliche Überschneidungen .................................................. 55
Abbildung 18: Register: ZUORDNUNG bearbeiten.................................................... 57
Abbildung 19: Zeilen in ZUORDNUNG ersetzen ....................................................... 58
Abbildung 20: Fenster: Erstellen einer Tabelle............................................................ 58
Abbildung 21: Register: Messbereich ändern .............................................................. 60
Abbildung 22: Register: FEHLER_CODE bearbeiten ................................................. 61
Abbildung 23: Fenster: Fehler eintragen ..................................................................... 61
Abbildung 24: Symbolleiste........................................................................................ 62
69
Anhang
9 Anhang
9.1 PL/SQL Skripte
Skriptname
Seite
Skript 1: ABLAUFSTRG_DB_NEU_ANLEGEN.SQL .............................................. 72
Skript 2: ABLAUFSTRG_DB_TABELLEN_ANLEGEN.SQL .................................. 73
Skript 3: ABLAUFSTRG_MANUELL.SQL............................................................... 74
Skript 4: ABLAUFSTRG_TAEGLICH.SQL .............................................................. 75
Skript 5: DATENBANKTABELLEN_ANLEGEN.SQL............................................. 77
Skript 6: DATENBANKTABELLEN_LEEREN.SQL ................................................ 82
Skript 7: DATENBANKTABELLEN_LOESCHEN.SQL........................................... 83
Skript 8: FEHL_AUTO_ANZEIGE.SQL.................................................................... 85
Skript 9: FEHL_AUTO_MARKIERUNG.SQL .......................................................... 87
Skript 10: FEHLER_EINTRAGEN.SQL .................................................................... 89
Skript 11: FUELLE_FEHL_INV_TAB.SQL .............................................................. 94
Skript 12: FUNKTION_DATUM_R_NR_IN_TAB.SQL............................................ 96
Skript 13: FUNKTION_FINDEANZAHL.SQL .......................................................... 97
Skript 14: FUNKTION_SONDERZEICHEN.SQL ..................................................... 97
Skript 15: FUNKTION_SPALTE_VORHANDEN.SQL............................................. 98
Skript 16: FUNKTION_TAB_VORHANDEN.SQL ................................................... 99
Skript 17: FUNTKION_ZUORDNUNG_PRUEFEN.SQL........................................ 100
Skript 18: INITUMGEBUNGSTABELLEN.SQL..................................................... 105
Skript 19: PROZEDUR_DATUM_VERBESSERN.SQL.......................................... 106
Skript 20: PROZEDUR_DB_SPALTEN_ANLEGEN.SQL ...................................... 109
Skript 21: PROZEDUR_DBMS_EXEC.SQL ........................................................... 111
70
Anhang
Skript 22: FROMS_COMMIT_ONLY.SQL ............................................................. 111
Skript 23: PROZEDUR_FORMS_FUELL_FEHL_AUTO_ANZEIGE.SQL............. 112
Skript 24: PROZEDUR_FORMS_MESSBEREICH_FEHL_UPDATE.SQL ............ 115
Skript 25: PROZEDUR_ZUB_DATEN_TMP_TAB_ANLEGEN.SQL .................... 117
Skript 26: SPOOL_FEHLER_TABS.SQL ................................................................ 119
Skript 27: SPOOL_KOPIEREN_NACH_ZUB_DATEN_TMP_TAB.SQL............... 121
Skript 28: SPOOL_ROHDATEN_EINTRAGEN.SQL ............................................. 123
Skript 29: SPOOL_ROHKORR.SQL........................................................................ 126
Skript 30: SPOOL_TAGMONATJAHR.SQL ........................................................... 128
Skript 31: UMGEBUNGSTABELLEN.SQL ............................................................ 131
Skript 32: ZEITTAB.SQL......................................................................................... 136
Skript 33: ZUORDNUNG.SQL ................................................................................ 138
71
Anhang
Skript 1: ABLAUFSTRG_DB_NEU_ANLEGEN.SQL
-- ACHTUNG:
-- DIE DATENBANKTABELLEN WERDEN KOMPLETT GELÖSCHT!!!
-- ACHTUNG
-- NUR STARTEN BEIM ERSTEN ANLEGEN DER DATENBANK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
----------------------------------------------------------------------------------------- Datei: Ablaufstrg_DB_neu_anlegen.sql
-- Erstellt: 08.11.2000
-- Beschreibung:
-- Anlegen der Datenbank mit Prozeduren.
-- Die Tabellen ZUB_DATEN_TMP_TAB und die Datenbanktabellen mit den Messwerten werden
-- erstellt, wenn ZUORDNUNG fehlerfrei ist. Es kann vorkommen das Sensoren (sensor),
-- die im gleichen Raum (tab_name) sind und auch noch die gleiche Raumnummer (r_nr)
-- besitzen, automatisch geändert werden. Prüfen Sie die Textdatei
-- "Datenbank_neu_anlegen" auf Fehlermeldungen.Falls Sensoren geändert wurden und Sie
-- nicht damit einverstanden sind, ändern Sie ZUORDNUNG und führen Sie dieses Skript
-- erneut aus!
-- Änderungen:
----------------------------------------------------------------------------------------SET SERVEROUTPUT ON
SET termout off;
SET echo off;
SET heading off;
--SET feedback off;
spool d:\zub_db\sql\meldungen\Datenbank_neu_anlegen.txt
BEGIN
DBMS_OUTPUT.PUT_LINE('-- Datenbank angelegt am '||to_char(SYSDATE,'dd.mm.yyyy
hh24:mi'));
END;
/
-- LÖSCHEN ALLER DATENBANKTABELLEN !!!
@@DB_Tabellen_loeschen.sql
-- INITIALISIERUNG DER DATENBANK
-Umgebungstabellen löschen und neu anlegen.
@@Umgebungstabellen.sql--!!!
-Umgebungstabellen initialisieren.
@@InitUmgebungstabellen.sql--!!!
---**********************************************************************
-- Tabelle ZUORDNUNG zur genauen Angabe der
-- Sensoren (Name bei Sauther,Sensorart, Raumnummer im Zub , Ort
-- (Art des Raumes), Minimaler Wert, Maximaler Wert).
-- Neue Sensoren hier editieren, alte herausnehmen. So erreicht man immer den
-- neuesten Stand bei einer Neuinitialisierung der Datenbank.
-- *********************************************************************
@@zuordnung.sql
/* PROZEDUREN ANLEGEN */
@@prozedur_dbms_exec.sql
@@funktion_findeAnzahl.sql
@@funktion_tab_vorhanden.sql
@@funktion_zuordnung_pruefen.sql
@@funktion_spalte_in_tabelle.sql
@@prozedur_zub_daten_tmp_tab_anlegen.sql
@@funktion_datum_r_nr_in_tab.sql
@@prozedur_db_spalte_anlegen.sql
@@prozedur_datum_verbessern.sql
@@funktion_sonderzeichen.sql
@@prozedur_forms_commit_only.sql
@@prozedur_forms_fuell_fehl_auto_anzeige.sql
@@prozedur_forms_messbereich_fehl_update.sql
-- ZUORDNUNG wird geprüft. Ist die Fehlerprüfung erfolgreich, werden die Tabellen
erstellt.
@@ablaufstrg_DB_Tabellen_anlegen.sql
72
Anhang
COMMIT;
EXIT;
Skript 2: ABLAUFSTRG_DB_TABELLEN_ANLEGEN.SQL
----------------------------------------------------------------------------------------- Datei: ABLAUFSTRG_DB_TABELLEN_ANLEGEN.SQL
-- Erstellt: 10.11.2000
-- Beschreibung:
-- Ablaufsteuerung für das Anlegen oder Löschen eines Messpunktes-- Die Tabelle ZUORDNUNG muss auf dem aktuellen Stand sein.
---- Bem.:
-Die Tabelle ZUB_DATEN_TMP_TAB kann im Notfall gelöscht werden, falls falsche
-Spalten vorhanden sind.
-Es muss aber sicher gestellt sein, dass ZUORDNUNG auf dem aktuellen Stand ist.
-Sie muss aber von Hand neu angelegt werden (siehe Umgebungstabellen.sql).
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON
SET termout off;
SET echo off;
SET heading off;
SET feedback off;
spool d:\zub_db\sql\meldungen\Datenbanktabellen.txt
-- INITIALISIERUNG DER DATENBANK
DECLARE
fehler_flag
NUMBER(2) := NULL;
BEGIN
DBMS_OUTPUT.PUT_LINE('-- Letzte Änderung der Tabellen '||to_char(SYSDATE,'dd.mm.yyyy
hh24:mi'));
-- Prüfen, ob die Werte in ZUORDNUNG mit denen aus ZUB_DATEN_TMP_TAB übereinstimmen.
-- Automatisches Anlegen der Datenbanktabellen aus den Tabellen 'ZUORDNUNG' und
'ANHANG'.
-- Die Datenbanktabellen werden erst angelegt, wenn die Tabelle ZUB_DATEN_TMP_TAB
-- vollständig ist.
-- Es wird hier der erste Versuch unternommen, die Messpunkte aus ZUORDNUNG zu
übernehmen
-- Mit der Option ANLEGEN entfällt die Prüfung von ZUB_DATEN_TMP_TAB
-- ZUB_DATEN_TMP_TAB kann nicht stimmen, bevor Sie nicht geändert wurde.
-- Keine Fehler in ZUORDNUNG. Die Tabelle ZUB_DATEN_TMP_TAB wird geändert.
fehler_flag := zuordnung_pruefen('ANLEGEN');
IF fehler_flag = 0 THEN
zub_daten_tmp_tab_anlegen;
COMMIT;
-- ZUORDNUNG wird vollständig geprüft.
-- Es wird der Fehler gefunden, falls nicht alle Spalten in ZUB_DATEN_TMP_TAB
-- eingetragen wurden. Andere Fehler werden erneut gefunden. Die Funktion
-- zuordnung_pruefen schreibt das fehler_flag in die Tabelle ZUORNUNG_GEPRUEFT,
welches
-- vor dem Anlegen der Datenbanktabellen gelesen wird. Ist es ungleich 0 wird
-- keine Datentabelle angelegt (s.u. DB_Tabellen_anlegen.sql).
DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- ZUORDNUNG wird erneut geprüft');
fehler_flag := zuordnung_pruefen('VOLL');
END IF;
END;
/
-- Anlegen von Tabellen und Spalten.
@@DB_Tabellen_anlegen;
-- Neues Anlegen der von Rohdaten_eintragen_kopieren.sql
-- Damit wird erreicht, dass immer nur Daten kopiert werden aus ZUB_DATEN_TMP_TAB,
73
Anhang
-- die noch nicht in ..._ROH_TAB vorhanden sind!
@@spool_Rohdaten_eintragen.sql
EXIT;
Skript 3: ABLAUFSTRG_MANUELL.SQL
----------------------------------------------------------------------------------------- Datei: ABLAUFSTRG_MANUELL.SQL
-- Erstellt: 20.11.2000
-- Beschreibung:
-- Ablaufsteuerung:
-- Es müssen die Tabellen ...FEHL_INV_TAB aus der Tabelle FEHL_TAB gefüllt werden.
-- Die Tabelle FEHL_TAB wird ausschliesslich in FORMS50 bearbeitet und die Verarbeitung
-- gestartet.
-- Die Tabellen ..._ROH_TAB werden mit den Tabellen ...FEHL_INV_TAB multipliziert
-- und in die Tabellen ..._ROHKORR_TAB eingetragen. Aus dieser werden die
-- Tagesmittelwerte
-- in die Tabellen ..._TAG_TAB eingetragen, aus denen wiederum ..._MONAT_TAB und zuletzt
-- aus ..._MONAT_TAB ..._JAHR_TAB erstellt.
-- ACHTUNG:
-- *** Im Skript "spool_TagMonatJahr.sql" kann eingestellt werden, wieviele Messwerte
-pro Tag aus ..._ROHKORR_TAB benötigt werden, damit ein Tageswert in
-..._TAG_TAB eingetragen wird.
-- Bem.:
-- 1) Die oben angegebene Zeichenkette ... bedeutet, dass es sich hierbei um
-die Datenbanktabellen aus ZUORDNUNG handelt, die in der Spalte
-'TAB_NAME' definiert wurden. Diese 'TAB_NAME'n werden mit
-Anhängseln aus der Tabelle ANHANG versehen
-(z.B. _ROH_TAB oder _FEHL_AUTO_TAB).
-- 2) Es werden Werte kopiert die in der Tabelle ZUORDNUNG vorhanden sind.
-Um neue Messpunkte anzulegen oder alte zu löschen, muss erst ZUORDNUNG
-aktualisiert werden und dann das Skript 'ablaufstrg_DB_Tabellen_anlegen.sql'
-gestartet werden.
-- Änderungen:
---------------------------------------------------------------------------------------SET SERVEROUTPUT ON
SET termout off;
SET echo off;
SET heading off;
SET FEEDBACK ON
-- ***Im Skript spool_TagMonatJahr.sql kann eingestellt werden, wieviele Messwerte pro
Tag aus ..._ROHKORR_TAB
--
benötigt werden, damit ein Tageswert in ..._TAG_TAB eingetragen wird.
@@spool_rohkorr.sql
@@spool_TagMonatJahr.sql
-- Eintragen von Werten in die Tabellen ..._FEHL_INV_TAB
SET SERVEROUTPUT ON
SET termout on;
SET echo on;
SET heading on;
SET FEEDBACK ON
spool d:\zub_db\sql\meldungen\Ablaufsteuerung_manuell.txt
BEGIN
DBMS_OUTPUT.PUT_LINE('-- Manuelle Ablaufsteuerung zuletzt gestartet am
'||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
END;
/
-- Füllen der Tabellen ..._FEHL_INV_TAB
-- DIESES SKRIPT WIRD AUS FORMS MANUELL GESTARTET
--@@fuelle_fehl_inv_tab.sql
74
Anhang
-- Füllen der ..._ROHKORR_TAB, ..._TAG_TAB, ..._MON_TAB, ...JAHR_TAB Tabellen
-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-Beachten Sie die Beschreibung (s.o. ***) von spool_TagMonatJahr.sql und stellen !!!
-Sie die minimale Anzahl der benötigten Werte ein.
!!!
@@rohkorr.sql
@@TagMonatJahr.sql
--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
COMMIT;
EXIT;
Skript 4: ABLAUFSTRG_TAEGLICH.SQL
----------------------------------------------------------------------------------------- Datei: ABLAUFSTRG_TAEGLICH.SQL
-- Erstellt: 20.11.2000
-- Beschreibung:
-- Ablaufsteuerung: Aufruf der verschiedenen Verarbeitungsstufen
-- zur Messwerterfassung für das ZUB
-- Die Daten werden aus der Tabelle ZUB_DATEN_TMP_TAB, die vom ZUB täglich mit den
-- Messwerten gefüllt wird in die Rohdatentabellen (..._ROH_TAB) eingefügt.
-- Die Tabelle ZUB_DATEN_TMP_TAB entählt die Hausadressen der Messtechnik als
Spaltennamen;
-- die ..._ROH_TAB Tabellen enthalten dagegen, die von der TGA zugewiesenen
-- Spaltennamen aus der Spalte 'SENSOR' aus der Tabelle ZUORDNUNG.
-- Desweiteren werden Mess- und Datumsfehler (s.u.) in die Tabellen ..._FEHL_AUTO_TAB
-- eingetragen.
-- Bem.:
-- 1) Die oben angegebene Zeichenkette ... bedeutet, dass es sich hierbei um
-die Datenbanktabellen aus ZUORDNUNG handelt, die in der Spalte
-'TAB_NAME' definiert wurden. Diese 'TAB_NAME'n werden mit
-Anhängseln aus der Tabelle ANHANG versehen
-(z.B. _ROH_TAB oder _FEHL_AUTO_TAB).
-- 2) Es werden Werte kopiert die in der Tabelle ZUORDNUNG vorhanden sind.
-Um neue Messpunkte anzulegen oder alte zu löschen, muss erst ZUORDNUNG
-aktualisiert werden und dann das Skript 'ablaufstrg_DB_Tabellen_anlegen.sql'
-gestartet werden.
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON
SET NEWPAGE 0
SET SPACE 0
SET LINESIZE 150
SET PAGESIZE 0
SET ECHO OFF
SET FEEDBACK OFF
SET HEADING OFF
SET TERMOUT off;
-- TEST TEST TEST
start d:\zub_db\sql\test\spool_kopieren_nach_zub_daten_tmp_tab.sql
-- ENDE TEST
spool d:\zub_db\sql\meldungen\Ablaufsteuerung_taeglich.txt
-- TEST TEST TEST
start d:\zub_db\sql\test\kopieren_nach_zub_daten_tmp_tab.sql
-- COMMIT;
-- ENDE TEST
BEGIN
DBMS_OUTPUT.PUT_LINE('Tägliche Ablaufsteuerung zuletzt gestartet am:
'||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
END;
/
75
Anhang
-- Anlegen und Aktualisieren der Zeittabelle zur Referenzierung der Datumseinträge.
@@zeittab;
-- Verbessern falscher Datums in ZUB_DATEN_TMP_TAB
BEGIN
DBMS_OUTPUT.PUT_LINE('------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Verbessern falscher Datums');
datum_verbessern;
DBMS_OUTPUT.PUT_LINE('------------------------------------------------------------------');
END;
/
COMMIT;
-- Dies ist eine Spool-Datei die aus spool_Rohdaten_eintragen.sql erstellt wurde.
-- Hier werden die Daten in die _TMP und _ROH_TAB Tabellen aufgenommen.
@@Rohdaten_eintragen.sql
-- Eintrag in Fehlertabellen der Datenbank (Prüfung, ob alle Daten vorhanden sind).
-- 1) Fehlende Datums
-- 2) Nicht vorhandene Messpunktwerte
-- 3) Eintrag von Abweichungen des Messbereichs.
@@fehler_eintragen.sql
SPOOL OFF;
COMMIT;
EXIT;
76
Anhang
Skript 5: DATENBANKTABELLEN_ANLEGEN.SQL
----------------------------------------------------------------------------------------- Datei: DATENBANKTABELLEN_ANLEGEN.SQL
-- Erstellt: 05.10.2000
-- Beschreibung:
-- Automatisches Anlegen der Oracle Tabellen, aus der Tabelle Zuordnung.
-- Es werden alle Datenpunkte aus der Tabelle Zuordnung überprüft; die
-- Tabellen geändert oder eine neue Tabelle erstellt.
---Änderungen:
------------------------------------------------------------------------------------------SET SERVEROUTPUT ON
DECLARE
-- Formate von verschiedenen Spalten
fehler_format VARCHAR2(20) := ' NUMBER(2)';
-- Die Spalten der Fehlertabellen werden
mit diesem Format gefüllt.
raum_format
VARCHAR2(20) := ' VARCHAR2(5)';
-- Die Raumnummern werden so angelegt.
-- Beim Anlegen der Tabellen werden verschiedenste Optionen angegeben
-- Date Tablespace mit den Messdaten des ZUB
-- Tabellen, die nur Spalten, aber keine Werte enthalten
db_zub_daten_storage VARCHAR2(150) := ' TABLESPACE ZUB_DATEN STORAGE (INITIAL 1M NEXT
10K MINEXTENTS 1 MAXEXTENTS 50)';
-- Temporäre Tabellen
db_zub_daten_tmp_storage
VARCHAR2(150) := ' TABLESPACE ZUB_DATEN STORAGE (INITIAL
20M NEXT 1M MINEXTENTS 1 MAXEXTENTS 50) PARALLEL (DEGREE 5) ';
-- Rohdaten und korrigierte Rohdaten sind sehr grosse Tabellen
db_zub_daten_roh_storage
VARCHAR2(150) := ' TABLESPACE ZUB_DATEN STORAGE (INITIAL
20M NEXT 20M MINEXTENTS 1 MAXEXTENTS 200) PARALLEL (DEGREE 5) ';
-- Tageswerte (Mittelwerte)
db_zub_daten_tag_storage
VARCHAR2(150) := ' TABLESPACE ZUB_DATEN STORAGE (INITIAL
10M NEXT 10M MINEXTENTS 1 MAXEXTENTS 50) PARALLEL (DEGREE 5) ';
-- Monats und Jahresmittelwerte
db_zub_daten_mon_jahr_storage VARCHAR2(150) := ' TABLESPACE ZUB_DATEN STORAGE (INITIAL 5M
NEXT 5M MINEXTENTS 1 MAXEXTENTS 50) PARALLEL (DEGREE 5) ';
-- Fehlertabellen
db_zub_daten_fehl_storage
VARCHAR2(150) := ' TABLESPACE ZUB_DATEN STORAGE (INITIAL
10M NEXT 10M MINEXTENTS 1 MAXEXTENTS 200) PARALLEL (DEGREE 5) ';
-- INDX Tablespace (Beschreibung wie oben)
db_indx_storage
VARCHAR2(150) := ' USING INDEX
1M NEXT 10K MINEXTENTS 1 MAXEXTENTS 50) ENABLE ';
db_indx_tmp_storage
VARCHAR2(150) := ' USING INDEX
5M NEXT 2M MINEXTENTS 1 MAXEXTENTS 50) ENABLE ';
db_indx_roh_storage
VARCHAR2(150) := ' USING INDEX
10M NEXT 10M MINEXTENTS 1 MAXEXTENTS 200) ENABLE ';
db_indx_tag_storage
VARCHAR2(150) := ' USING INDEX
5M NEXT 5M MINEXTENTS 1 MAXEXTENTS 200) ENABLE ';
db_indx_mon_jahr_storage VARCHAR2(150) := ' USING INDEX
5M NEXT 5M MINEXTENTS 1 MAXEXTENTS 200) ENABLE ';
db_indx_fehl_storage
VARCHAR2(150) := ' USING INDEX
5M NEXT 5M MINEXTENTS 1 MAXEXTENTS 200) ENABLE ';
TABLESPACE INDX STORAGE (INITIAL
TABLESPACE INDX STORAGE (INITIAL
TABLESPACE INDX STORAGE (INITIAL
TABLESPACE INDX STORAGE (INITIAL
TABLESPACE INDX STORAGE (INITIAL
TABLESPACE INDX STORAGE (INITIAL
-- Variablen und CURSOR für die Verarbeitung.
c_dbms_tab_name
INTEGER;
c_dbms_spalte
INTEGER;
c_dbms_copy
INTEGER;
dummy
INTEGER;
tmp_name
Zuordnung.tab_name%TYPE; -- Temporärer Speicher für
aktuellen Tabellennamen (DBMS_SQL Funktion)
77
Anhang
anhaengsel
der Tabelle Anhang
spalte_vorh
für 'spalte'
spalte_sensor
flag_fehler_zuordnung
n_exception_flag
anhang.anhang%TYPE :=' ';
-- Variable zur Selektion
CURSOR c_namen
IS SELECT DISTINCT upper(tab_name) tab_name from zuordnung;
user_tab_columns.column_name%TYPE;
-- Zweite Variable
VARCHAR2(30);
NUMBER(2);
NUMBER(6);
CURSOR c_spalten
IS SELECT upper(z.sensor) sensor, upper(hw_adr) hw_adr,
upper(format) format FROM zuordnung z WHERE upper(z.tab_name)=upper(tmp_name);
CURSOR c_anhang
IS SELECT upper(anhang) anhang FROM anhang;
CURSOR c_spalte_vorh IS
SELECT user_tab.column_name FROM user_tab_columns user_tab
WHERE upper(tmp_name) = upper(user_tab.table_name)
AND upper(user_tab.column_name) = upper(spalte_sensor);
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
DBMS_OUTPUT.PUT_LINE('--*****************************************************--');
DBMS_OUTPUT.PUT_LINE('-DB_Tabellen_anlegen.sql');
SELECT flag INTO flag_fehler_zuordnung FROM zuordnung_geprueft;
IF flag_fehler_zuordnung != 0 THEN
DBMS_OUTPUT.PUT_LINE('-- FEHLER in ZUORDNUNG!!!');
DBMS_OUTPUT.PUT_LINE('-Es werden keine Datenbanktabellen
angelegt oder verändert.');
DBMS_OUTPUT.PUT_LINE('-Verbessern Sie den/die oben genannten
Fehler und starten Sie das Skript erneut.');
-- Das gewünschten flag Fehler heraussuchen. Der flag_fehler_zuordnung ist nach
Bits geordnet (siehe prouzedur_zuordnung_pruefen.sql)
ELSE
-- ZUORDNUNG ist mit ZUB_DATEN_TMP_TAB abgeglichen. Die Datenbanktabellen werden
angelegt oder geändert.
c_dbms_tab_name
:= DBMS_SQL.OPEN_CURSOR;
c_dbms_spalte
:= DBMS_SQL.OPEN_CURSOR;
c_dbms_copy
:= DBMS_SQL.OPEN_CURSOR;
-- Alle Tabellen mit Spalten aus Zuordnung anlegen.
FOR n IN c_namen LOOP
n_exception_flag := 1000;
-- kopieren des Tabellennamens in eine temporäre Variable (sonst
funktioniert CURSOR c_spalten nicht)
tmp_name := upper(n.tab_name);
-- Anlegen der Tabellennamen, wie sie in der Tabelle Zuordnung stehen.
-- Prüfen, ob die Standardtabellen vorhanden sind.
IF tab_vorhanden(tmp_name) = FALSE THEN
-- Tabelle nicht vorhanden. Es werden die Tabellen mit allen
Spalten aus ZUORDNUNG für die Datenbank erstellt.
-- Die Tabelle tmp_name ist nur für das Anlegen der anderen
Tabellen zuständig. Sie bleibt leer.
n_exception_flag := 2000;
DBMS_SQL.PARSE(c_dbms_tab_name,'CREATE TABLE ' || tmp_name || '
(datum DATE, r_nr '||raum_format||') '||db_zub_daten_storage,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_tab_name);
COMMIT;
DBMS_SQL.PARSE(c_dbms_tab_name,'ALTER TABLE '|| tmp_name ||' ADD
CONSTRAINT pk'||n.tab_name||' PRIMARY KEY (datum, r_nr)
'||db_indx_storage,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_tab_name);
COMMIT;
-- Anlegen der Fehlertabellen
DBMS_SQL.PARSE(c_dbms_tab_name,'CREATE TABLE ' || tmp_name ||
'_FEHL_AUTO_TAB (datum DATE, r_nr '||raum_format||',check_flag NUMBER(1) DEFAULT NULL,
Bearbeiter VARCHAR2(30)) '||db_zub_daten_fehl_storage,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_tab_name);
COMMIT;
DBMS_SQL.PARSE(c_dbms_tab_name,'ALTER TABLE '|| tmp_name
||'_FEHL_AUTO_TAB ADD CONSTRAINT pk'||n.tab_name||'_FEHL_AUTO_TAB PRIMARY KEY (datum,
r_nr) '||db_indx_fehl_storage,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_tab_name);
COMMIT;
-- Fehlertabelle extra erstellen, da Sie später ein anderes NUMBER
Format erhält.
78
Anhang
DBMS_SQL.PARSE(c_dbms_tab_name,'CREATE TABLE ' || tmp_name ||
'_FEHL_INV_TAB (datum DATE, r_nr '||raum_format||')
'||db_zub_daten_fehl_storage,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_tab_name);
COMMIT;
DBMS_SQL.PARSE(c_dbms_tab_name,'ALTER TABLE '|| tmp_name
||'_FEHL_INV_TAB ADD CONSTRAINT pk'||n.tab_name||'_FEHL_INV_TAB PRIMARY KEY (datum,
r_nr) '|| db_indx_fehl_storage,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_tab_name);
COMMIT;
DBMS_OUTPUT.PUT_LINE('--');
DBMS_OUTPUT.PUT_LINE('--');
DBMS_OUTPUT.PUT_LINE('-Tabelle ' || tmp_name || '
erstellt.');
FOR spalte IN c_spalten LOOP
n_exception_flag := 3000;
-- Einfügen der Spalten
IF
spalte_in_tabelle('ZUB_DATEN_TMP_TAB',UPPER(spalte.hw_adr)) =TRUE AND
spalte_in_tabelle(tmp_name,spalte.sensor) = FALSE THEN
-- Die Spalte ist in ZUB_DATEN_TMP_TAB vorhanden, aber
nicht in der DB Tabellen.
db_spalte_anlegen(tmp_name,spalte.sensor,spalte.format);
-- Fehlertabellen mit Spalten werden automatisch im
Format Number(2) angelegt.
db_spalte_anlegen(tmp_name||'_FEHL_AUTO_TAB',spalte.sensor,spalte.format);
db_spalte_anlegen(tmp_name||'_FEHL_INV_TAB',spalte.sensor,spalte.format);
DBMS_OUTPUT.PUT_LINE('-Spalte ' ||
spalte.sensor || ' eingefügt.');
COMMIT;
ELSIF
spalte_in_tabelle('ZUB_DATEN_TMP_TAB',UPPER(spalte.hw_adr)) =FALSE THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler oder Warnung:
Tabelle neu angelegt und der Versuch Spalten einzufügen.');
DBMS_OUTPUT.PUT_LINE('-Spalte: ' ||
spalte.sensor || ' für Tabelle '|| tmp_name||' in ZUORDNUNG nicht als
'||spalte.hw_adr||' in ZUB_DATEN_TMP_TAB gefunden.');
DBMS_OUTPUT.PUT_LINE('-Spalte wird
nicht angelegt.');
DBMS_OUTPUT.PUT_LINE('-Prüfen Sie, ob
nicht eine Primary Key Verletzung in ZUORDNUNG auftrat.');
END IF;
END LOOP;
-- Kopieren der Tabelle 'tmp_name' in die Datenbanktabellen mit
den Anhängseln aus der Tabelle 'ANHANG'
FOR a IN c_anhang
LOOP
n_exception_flag := 4000;
-- Tabellen aus ZUORDNUNG mit Anhang aus Tabelle ANHANG
erstellen.
IF a.anhang !='_FEHL_AUTO_TAB' AND a.anhang
!='_FEHL_INV_TAB' THEN -- 1:1 kopieren aller Tabellen bis auf die Fehlertabellen (diese
werden oben angelegt).
-- Unterscheiden, welche Tabelle gerade angelegt
wird.
IF a.anhang = '_ROH_TAB' OR a.anhang =
'_ROHKORR_TAB' THEN
n_exception_flag := 4010;
DBMS_SQL.PARSE(c_dbms_copy,'CREATE TABLE '
|| tmp_name || a.anhang || ' '||db_zub_daten_roh_storage||' AS (SELECT * FROM ' ||
n.tab_name || ')',DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_copy);
COMMIT;
-- PRIMARY KEY hinzufügen
DBMS_SQL.PARSE(c_dbms_copy,'ALTER TABLE ' ||
tmp_name || a.anhang || ' ADD PRIMARY KEY (datum, r_nr)
'||db_indx_roh_storage,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_copy);
ELSIF
a.anhang = '_TAG_TAB' THEN
n_exception_flag := 4020;
DBMS_SQL.PARSE(c_dbms_copy,'CREATE TABLE '
|| tmp_name || a.anhang || ' '||db_zub_daten_tag_storage||' AS (SELECT * FROM ' ||
n.tab_name || ')',DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_copy);
79
Anhang
COMMIT;
-- PRIMARY KEY hinzufügen
DBMS_SQL.PARSE(c_dbms_copy,'ALTER TABLE ' ||
tmp_name || a.anhang || ' ADD PRIMARY KEY (datum, r_nr)
'||db_indx_tag_storage,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_copy);
ELSIF
a.anhang = '_MONAT_TAB' OR a.anhang =
'_JAHR_TAB' THEN
n_exception_flag := 4030;
DBMS_SQL.PARSE(c_dbms_copy,'CREATE TABLE '
|| tmp_name || a.anhang || ' '||db_zub_daten_mon_jahr_storage||' AS (SELECT * FROM ' ||
n.tab_name || ')',DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_copy);
COMMIT;
-- PRIMARY KEY hinzufügen
DBMS_SQL.PARSE(c_dbms_copy,'ALTER TABLE ' ||
tmp_name || a.anhang || ' ADD PRIMARY KEY (datum, r_nr)
'||db_indx_mon_jahr_storage,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_copy);
ELSE
n_exception_flag := 4040;
-- _TMP_TAB
DBMS_SQL.PARSE(c_dbms_copy,'CREATE TABLE '
|| tmp_name || a.anhang || ' '||db_zub_daten_tmp_storage||' AS (SELECT * FROM ' ||
n.tab_name || ')',DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_copy);
COMMIT;
-- PRIMARY KEY hinzufügen
DBMS_SQL.PARSE(c_dbms_copy,'ALTER TABLE ' ||
tmp_name || a.anhang || ' ADD PRIMARY KEY (datum, r_nr)
'||db_indx_tmp_storage,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_copy);
END IF;
n_exception_flag := 4050;
COMMIT;
END IF;
-- Die Fehlertabellen wurden oben schon angelegt, aber für
eine Ausgabe ist das übersichtlicher.
DBMS_OUTPUT.PUT_LINE('--');
DBMS_OUTPUT.PUT_LINE('-Tabelle ' || tmp_name
||a.anhang ||' als Abbildung von '||tmp_name||' erstellt.');
END LOOP;
ELSE
-- Tabelle ist vorhanden! Gibt es schon diese Spalte?
n_exception_flag := 5000;
FOR spalte IN c_spalten LOOP
-- Spaltenname aus Tabelle tmp_name selektieren.
-DBMS_OUTPUT.PUT_LINE('-- Spalte: ' || spalte || ' Tab_name:
' || tmp_name);
IF
spalte_in_tabelle('ZUB_DATEN_TMP_TAB',UPPER(spalte.hw_adr)) =TRUE AND
spalte_in_tabelle(tmp_name,spalte.sensor) = FALSE THEN
-- Die Spalte ist in ZUB_DATEN_TMP_TAB vorhanden,
aber nicht in der DB Tabellen.
spalte_sensor := spalte.sensor;
OPEN c_spalte_vorh;
FETCH c_spalte_vorh INTO spalte_vorh; -Selektieren des Spaltennamens aus der DB Tabelle.
IF c_spalte_vorh%NOTFOUND THEN
spalte_vorh := NULL;
END IF;
CLOSE c_spalte_vorh;
-- Gibt es Spaltennamen?
IF spalte_vorh IS NULL THEN
--DBMS_OUTPUT.PUT_LINE('-- Neue Spalte: ' ||
spalte.sensor || ' in Tabelle: ' || tmp_name);
anhaengsel := ''; -- anhängsel initialiseren
für LOOP
OPEN c_anhang;
-- Eintrag in die Tabelle 'tmp_name' und in
die Tabellen 'tmp_name' mit ihren Anhängseln aus der Tabelle 'ANHANG'.
LOOP
80
Anhang
db_spalte_anlegen(tmp_name||anhaengsel,spalte.sensor,spalte.format);
FETCH c_anhang INTO anhaengsel;
EXIT WHEN c_anhang%NOTFOUND;
END LOOP;
DBMS_OUTPUT.PUT_LINE('-- Neue Spalte: ' ||
spalte.sensor || ' in DB Tabellen mit: ' || tmp_name ||' eingefügt.');
COMMIT;
CLOSE c_anhang;
END IF;
ELSIF
spalte_in_tabelle('ZUB_DATEN_TMP_TAB',UPPER(spalte.hw_adr)) = FALSE THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler oder Warnung: Beim
Einfügen einer neuen Spalte in bestehende Tabelle.');
DBMS_OUTPUT.PUT_LINE('-Spalte: ' ||
spalte.sensor || ' für Tabelle '|| tmp_name||' in ZUORDNUNG nicht als
'||spalte.hw_adr||' in ZUB_DATEN_TMP_TAB gefunden.');
DBMS_OUTPUT.PUT_LINE('-Spalte wird
nicht angelegt.');
DBMS_OUTPUT.PUT_LINE('-Prüfen Sie, ob
nicht eine Primary Key Verletzung in ZUORDNUNG auftrat.');
END IF;
END LOOP;
COMMIT;
END IF;
DBMS_OUTPUT.PUT_LINE('--');
DBMS_OUTPUT.PUT_LINE('--');
END LOOP;
DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------');
DBMS_SQL.CLOSE_CURSOR(c_dbms_tab_name);
DBMS_SQL.CLOSE_CURSOR(c_dbms_spalte);
DBMS_SQL.CLOSE_CURSOR(c_dbms_copy);
END IF;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler: Exception OTHERS in DB_Tabellen_anlegen.sql .');
DBMS_OUTPUT.PUT_LINE('-Flag: '||n_exception_flag||'.');
IF c_spalte_vorh%ISOPEN THEN
CLOSE c_spalte_vorh;
END IF;
IF c_namen%ISOPEN THEN
CLOSE c_namen;
END IF;
IF c_spalten%ISOPEN THEN
CLOSE c_spalten;
END IF;
IF c_anhang%ISOPEN THEN
CLOSE c_anhang;
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms_tab_name) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_tab_name);
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms_spalte) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_spalte);
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms_copy) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_copy);
END IF;
RAISE;
END;
/
COMMIT;
--select table_name from user_tables;
--desc Klima;
--desc StdR;
81
Anhang
Skript 6: DATENBANKTABELLEN_LEEREN.SQL
----------------------------------------------------------------------------------------- ACHTUNG: Dieses Skript darf nur bei Inbetriebnahme der Datenbank gestartet werden.
----------------------------------------------------------------------------------------- Datei: DATENBANKTABELLEN_LEEREN.SQL
-- Erstellt: 05.10.2000
-- Beschreibung:
-- Leeren aller Datenbanktabellen mit den Anhängseln aus der Tabelle 'Anhang'
-- und der Datenbanktabelle ohne Anhängsel.
---Änderungen:
----------------------------------------------------------------------------------------SET SERVEROUTPUT ON
-- Löschen der Tabellen und neu anlegen im unteren Teil
-- kann hier auch automatisiert werden.
DECLARE
c_dbms_del
INTEGER;
dummy
INTEGER;
name
Zuordnung.tab_name%TYPE;
tmp_name
Zuordnung.tab_name%TYPE;
CURSOR c_namen IS SELECT DISTINCT upper(tab_name) from zuordnung;
CURSOR c_anhang IS SELECT upper(anhang) FROM anhang;
anhaengsel
anhang.anhang%TYPE;
BEGIN
c_dbms_del
:= dbms_sql.open_cursor;
OPEN c_namen;
-- Alle Tabellen mit Spalten aus Zuordnung anlegen.
LOOP
FETCH c_namen INTO name;
EXIT WHEN c_namen%NOTFOUND;
-- Anlegen der Tabellennamen, wie sie in der Tabelle Zuordnung stehen.
-- Prüfen, ob die Standardtabellen vorhanden sind.
tmp_name := upper(name);
IF tab_vorhanden(tmp_name) = TRUE THEN
DBMS_SQL.PARSE(c_dbms_del,'TRUNCATE TABLE ' || tmp_name,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_del);
DBMS_OUTPUT.PUT_LINE('Tabelle ' || tmp_name || ' geleert.');
END IF;
OPEN c_anhang;
LOOP
FETCH c_anhang INTO anhaengsel;
EXIT WHEN c_anhang%NOTFOUND;
name := upper(tmp_name || anhaengsel);
IF tab_vorhanden(name) = TRUE THEN
DBMS_SQL.PARSE(c_dbms_del,'TRUNCATE TABLE ' ||
name,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_del);
DBMS_OUTPUT.PUT_LINE('Tabelle ' || name || ' geleert.');
ELSE
DBMS_OUTPUT.PUT_LINE('Tabelle ' || name || ' nicht vorhanden.');
END IF;
COMMIT;
END LOOP;
CLOSE c_anhang;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(c_dbms_del);
CLOSE c_namen;
EXCEPTION
WHEN OTHERS THEN
IF c_namen%ISOPEN THEN
CLOSE c_anhang;
END IF;
IF c_namen%ISOPEN THEN
CLOSE c_namen;
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms_del) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_del);
END IF;
RAISE;
END;
82
Anhang
/
COMMIT;
Skript 7: DATENBANKTABELLEN_LOESCHEN.SQL
----------------------------------------------------------------------------------------- ACHTUNG: Dieses Skript darf nur bei Inbetriebnahme der Datenbank gestartet werden.
----------------------------------------------------------------------------------------- Datei: DATENBANKTABELLEN_LOESCHEN.SQL
-- Erstellt: 05.10.2000
-- Beschreibung:
-- Löschen aller Datenbanktabellen mit den Anhängseln aus der Tabelle 'Anhang'
-- und der Datenbanktabelle ohne Anhängsel.
---Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON
-- Löschen der Tabellen und neu anlegen im unteren Teil
-- kann hier auch automatisiert werden.
DECLARE
c_dbms_del
INTEGER;
dummy
INTEGER;
name
Zuordnung.tab_name%TYPE;
tmp_name
Zuordnung.tab_name%TYPE;
CURSOR c_namen IS SELECT DISTINCT upper(tab_name) from zuordnung;
CURSOR c_anhang IS SELECT upper(anhang) FROM anhang;
anhaengsel
anhang.anhang%TYPE;
zaehl
NUMBER(6) := 0;
-------------------------------------------------------------------------
BEGIN
DBMS_OUTPUT.PUT_LINE('Datenbanktabellen löschen!');
DBMS_OUTPUT.ENABLE(1000000);
c_dbms_del
:= dbms_sql.open_cursor;
-- Alle Tabellen mit Spalten aus Zuordnung anlegen.
OPEN c_namen;
LOOP
FETCH c_namen INTO name;
EXIT WHEN c_namen%NOTFOUND;
zaehl := zaehl + 1;
-- Anlegen der Tabellennamen, wie sie in der Tabelle Zuordnung stehen.
-- Prüfen, ob die Standardtabellen vorhanden sind.
tmp_name := upper(name);
IF tab_vorhanden(tmp_name) = TRUE THEN
DBMS_SQL.PARSE(c_dbms_del,'DROP TABLE ' || tmp_name,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_del);
DBMS_OUTPUT.PUT_LINE('Tabelle ' || tmp_name || ' gelöscht.');
END IF;
OPEN c_anhang;
LOOP
FETCH c_anhang INTO anhaengsel;
EXIT WHEN c_anhang%NOTFOUND;
name := upper(tmp_name || anhaengsel);
IF tab_vorhanden(name) = TRUE THEN
DBMS_SQL.PARSE(c_dbms_del,'DROP TABLE ' || name,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms_del);
DBMS_OUTPUT.PUT_LINE('Tabelle ' || name || ' gelöscht.');
ELSE
DBMS_OUTPUT.PUT_LINE('Tabelle ' || name || ' nicht vorhanden.');
END IF;
83
Anhang
COMMIT;
END LOOP;
CLOSE c_anhang;
END LOOP;
DBMS_OUTPUT.PUT_LINE('Es wurden ' || zaehl || ' Tabellen gelöscht.');
DBMS_SQL.CLOSE_CURSOR(c_dbms_del);
CLOSE c_namen;
EXCEPTION
WHEN OTHERS THEN
IF c_namen%ISOPEN THEN
CLOSE c_anhang;
END IF;
IF c_namen%ISOPEN THEN
CLOSE c_namen;
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms_del) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_del);
END IF;
RAISE;
END;
/
COMMIT;
84
Anhang
Skript 8: FEHL_AUTO_ANZEIGE.SQL
----------------------------------------------------------------------------------------- Datei: FEHL_AUTO_ANZEIGE.SQL
-- Erstellt: 07.12.2000
-- Beschreibung:
-- Füllt die Tabelle FEHL_AUTO_ANZEIGE_TAB für FORMS50 mit Werten
-- Sehen Sie in die Beschreibung von der PROZEDUR_FUELL_FEHL_AUTO_ANZEIGE.SQL
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON
SET NEWPAGE 1
SET LINESIZE 200
SET SPACE 1
--SET ECHO OFF
--SET FEEDBACK OFF
SET HEADING OFF
SET TERMOUT off;
SPOOL d:\zub_db\sql\meldungen\fehl_auto_anzeige.txt
DECLARE
CURSOR c_tabs IS
SELECT DISTINCT upper(tab_name) tab_name, upper(sensor) sensor, upper(r_nr) r_nr FROM
ZUORDNUNG
ORDER BY tab_name, r_nr, sensor;
n_exception_flag NUMBER(6);
ausgabe VARCHAR2(100);
fehl_nr NUMBER(2);
dummy INTEGER;
c_dbms INTEGER;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
DBMS_OUTPUT.PUT_LINE('-- Datei erstellt am '||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('Füllen der Tabelle FEHL_AUTO_ANZEIGE_TAB.');
DBMS_OUTPUT.PUT_LINE('.');
c_dbms := DBMS_SQL.OPEN_CURSOR;
n_exception_flag := 0;
-- Leeren der Tabelle
ausgabe := 'TRUNCATE TABLE FEHL_AUTO_ANZEIGE_TAB';
DBMS_SQL.PARSE(c_dbms,ausgabe,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms);
DBMS_SQL.CLOSE_CURSOR(c_dbms);
n_exception_flag := 100;
-- Füllen der Tabelle
FOR c IN c_tabs LOOP
n_exception_flag := 1000;
-- Aufruf:
Tabellenname, Sensor,
Raumnummer, Fehlerkennung
fuell_fehl_auto_anzeige(c.tab_name,
c.sensor,
c.r_nr,
1);
n_exception_flag := 2000;
fuell_fehl_auto_anzeige(c.tab_name, c.sensor, c.r_nr, 2);
n_exception_flag := 3000;
fuell_fehl_auto_anzeige(c.tab_name, c.sensor, c.r_nr, 3);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler: Exception OTHERS in FEHL_AUTO_ANZEIGE_SQL.sql
.');
DBMS_OUTPUT.PUT_LINE('-Flag: '||n_exception_flag||'.');
IF c_tabs%ISOPEN THEN
CLOSE c_tabs;
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms);
85
Anhang
END IF;
RAISE;
END;
/
select count(*) eintraege from FEHL_AUTO_ANZEIGE_TAB;
select tab_name , sensor , r_nr , anz_fehler , to_char(anf_dat,'dd.mm.yyyy hh24:mi')
anfangsdatum , to_char(end_dat,'dd.mm.yyyy hh24:mi') enddatum , fehler_nr from
FEHL_AUTO_ANZEIGE_TAB
order by tab_name,fehler_nr, anf_dat, r_nr, sensor;
SPOOL OFF;
EXIT;
86
Anhang
Skript 9: FEHL_AUTO_MARKIERUNG.SQL
----------------------------------------------------------------------------------------- Datei: FEHL_AUTO_MARKIERUNG.SQL
-- Erstellt: 09.12.2000
-- Beschreibung:
-- Schreibt das Check_flag und den Bearbeiter in die jeweiligen Fehlertabellen.
-- Dazu wird die Tabelle FEHL_AUTO_ANZEIGE_TAB genutzt, die von der SQL Datei
-- FEHL_AUTO_ANZEIGE.SQL gefüllt wird.
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON
SET NEWPAGE 0
SET SPACE 2
SET LINESIZE 200
SET PAGESIZE 0
SET ECHO OFF
SET FEEDBACK OFF
SET HEADING OFF
SET TERMOUT off;
SPOOL d:\zub_db\sql\meldungen\fehl_auto_markierung.txt
DECLARE
n_exception_flag NUMBER(6);
ausgabe VARCHAR2(255);
fehl_nr NUMBER(2);
dummy INTEGER;
c_dbms INTEGER;
CURSOR c_flag IS
SELECT * FROM fehl_auto_anzeige_tab
WHERE check_flag IS NOT NULL;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
DBMS_OUTPUT.PUT_LINE('-- Datei erstellt am '||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('Markieren der Tabellen. FEHL_AUTO_TAB.');
c_dbms := DBMS_SQL.OPEN_CURSOR;
n_exception_flag := 0;
FOR c IN c_flag LOOP
IF c.r_nr != 'ALLE' THEN
n_exception_flag := 1000;
ausgabe := 'UPDATE '||c.tab_name||'_FEHL_AUTO_TAB SET check_flag = 1,
Bearbeiter = '||CHR(39)||c.Bearbeiter||CHR(39)||' WHERE datum BETWEEN :anf_dat AND
:end_dat AND '||c.sensor||' = '||c.fehler_nr||' AND upper(r_nr) =
'||CHR(39)||UPPER(c.r_nr)||CHR(39);
ELSE
-- Es wird das Flag für alle Raumnummern und Sensoren gesetzt.
-- Dies kommt von einen fehlenden Datum in ZUB_DATEN_TMP_TAB
n_exception_flag := 1500;
ausgabe := 'UPDATE '||c.tab_name||'_FEHL_AUTO_TAB SET check_flag = 1,
Bearbeiter = '||CHR(39)||c.Bearbeiter||CHR(39)||' WHERE datum BETWEEN :anf_dat AND
:end_dat';
END IF;
n_exception_flag := 2000;
DBMS_OUTPUT.PUT_LINE(ausgabe);
DBMS_OUTPUT.PUT_LINE('
:anf_dat =
'||to_char(c.anf_dat,'dd.mm.yyyy hh24:mi')||' :end_dat =
'||to_char(c.end_dat,'dd.mm.yyyy hh24:mi'));
DBMS_SQL.PARSE(c_dbms,ausgabe,DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(c_dbms,':anf_dat', c.anf_dat);
DBMS_SQL.BIND_VARIABLE(c_dbms,':end_dat',c.end_dat);
dummy := DBMS_SQL.EXECUTE(c_dbms);
END LOOP;
DBMS_SQL.CLOSE_CURSOR(c_dbms);
-- Füllen der Tabelle
87
Anhang
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler: Exception OTHERS in FEHL_AUTO_MARKIERUNG.SQL
.');
DBMS_OUTPUT.PUT_LINE('-Flag: '||n_exception_flag||'.');
IF DBMS_SQL.IS_OPEN(c_dbms) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms);
END IF;
RAISE;
END;
/
select * from FEHL_AUTO_ANZEIGE_TAB
WHERE check_flag = 1
order by tab_name,fehler_nr, anf_dat, r_nr, sensor;
SPOOL OFF;
EXIT;
88
Anhang
Skript 10: FEHLER_EINTRAGEN.SQL
----------------------------------------------------------------------------------------- Datei: FEHLER_EINTRAGEN.SQL
-- Erstellt: 13.11.2000
-- Beschreibung:
-- Dieses Skript prüft Fehler in ZUB_DATEN_TMP_TAB und trägt die Fehler in die einzelnen
-- Datenbanktabellen ein.
-- FEHLER 1: Sind alle Datums vorhanden?
-- FEHLER 2: Sind die Werte vorhanden?
-- FEHLER 3: Sind die Werte im Messbereich?
-- Die fehlerhaften Werte werden bei Bedarf in FORMS in die Tabellen ..._FEHL_AUTO_TAB
-- mit obiger Fehlernummer eingetragen.
-----
Bem.:
Es werden nur neuere Datums durchsucht, als die in den Rohdaten stehen.
Dazu wird das neueste Datum von einem Sensor mit seiner Raumnummer
aus ..._ROH_TAB selektiert und dass neueste Datum von ZUB_DATEN_TMP_TAB
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON
--SET termout off;
--SET echo off;
--SET heading off;
--SET feedback off;
SET LINESIZE 300
--SPOOL d:\zub_db\sql\meldungen\fehler_eintragen.txt
-- Die Datei wird in Ablaufsteuerung Täglich eingetragen.
DECLARE
-- CURSOR FÜR DEN EINTRAG IN DIE ROHDATEN-, TMP-, UND FEHLERTABELLEN
d_anfang
DATE; -- ältestes Datum in ..._TMP_TAB
d_ende
DATE; -- neuestes Datum in ..._TMP_TAB
--d_fehlt
DATE; -- ungültiges Datum
d_mess
DATE; -- ausserhalb des messbereichs
n_exception_flag
NUMBER(10) ;
hk
CHAR(1); -- Abgespeichertes Hochkomma in Tabelle.
ausgabe
VARCHAR2(255);
ausgabe1
VARCHAR2(100);
ausgabe2
VARCHAR2(100);
ausgabe3
VARCHAR2(100);
-- Tabellennamen und Spaltennamen, Minimal- und Maximalwerte
CURSOR c_zuordnung IS
SELECT UPPER(hw_adr) hw_adr, UPPER(r_nr) r_nr ,UPPER(sensor) sensor, UPPER(tab_name)
tab_name, minwert, maxwert FROM zuordnung -- TEST (schnellerer Verlauf) -> WHERE hw_adr
='H00100';
ORDER BY tab_name, r_nr;
--ORDER BY tab_name, r_nr;
-- Cursor gibt die fehlenden Datums in ZUB_DATEN_TMP_TAB (falsche Datums wurden schon
korrigiert)
CURSOR c_datum_fehlt IS
SELECT ref_zeit FROM zeittab
WHERE ref_zeit BETWEEN d_anfang AND d_ende
MINUS
SELECT to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') from zub_daten_tmp_tab;
-- CURSOR findet Werte ausserhalb des Messbereichs, die nicht NULL sind.
-- Es muss in diesem Fall ein DBMS_SQL Cursor verwendet werden, da der Spaltenname noch
nicht selektiert ist.
--CURSOR c_mess IS
--SELECT to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') FROM zub_daten_tmp_tab
--WHERE spaltenname NOT BETWEEN minimalwert AND maximalwert
--AND spaltenname IS NOT NULL;
-- CURSOR findet nicht vorhandene Werte, die ein Datum haben, aber NULL sind.
--CURSOR c_null IS
--SELECT to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') FROM zub_daten_tmp_tab
--WHERE spaltenname IS NULL;
89
Anhang
-- DBMS_SQL
dummy
c_dbms
c_dbms1
c_dbms_mess
INTEGER;
INTEGER;
INTEGER;
INTEGER;
------------------------------------------------------------------------------------------------------------------------------------------------------ BEGINN DES SKRIPTS
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
c_dbms := DBMS_SQL.OPEN_CURSOR;
c_dbms1 := DBMS_SQL.OPEN_CURSOR;
c_dbms_mess := DBMS_SQL.OPEN_CURSOR;
DBMS_OUTPUT.PUT_LINE('---------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- SQL DATEI: FEHLER_EINTRAGEN');
-- Das Hochkomma ' in hk speichern!
SELECT strich INTO hk FROM hochkomma;
-- neuestes Datum aus ZUB_DATEN_TMP_TAB d_ende ablegen.
--SELECT max(to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') ) INTO d_ende FROM
zub_daten_tmp_tab;
--DBMS_OUTPUT.PUT_LINE('-- Ende: ' || to_char(d_ende,'dd.mm hh24:mi'));
<<hauptschleife>>
FOR z IN c_zuordnung LOOP
-- Selektieren des jüngsten und ältesten Datums bei einem Sensor mit bestimmter
R_Nr in den Tabellen ..._TMP_TAB
ausgabe := 'SELECT min(datum), max(datum) FROM '||z.tab_name||'_TMP_TAB WHERE
r_nr = :z_r_nr1 AND '||z.sensor||' IS NOT NULL';
DBMS_SQL.PARSE(c_dbms,ausgabe,DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN(c_dbms, 1, d_anfang);
DBMS_SQL.DEFINE_COLUMN(c_dbms, 2, d_ende);
DBMS_SQL.BIND_VARIABLE(c_dbms, ':z_r_nr1',z.r_nr);
dummy := DBMS_SQL.EXECUTE(c_dbms);
IF DBMS_SQL.FETCH_ROWS(c_dbms) > 0 THEN
DBMS_SQL.COLUMN_VALUE(c_dbms, 1, d_anfang);
--DBMS_OUTPUT.PUT_LINE('Maximales Datum :' ||
to_char(d_anfang,'dd.mm.yyyy hh24:mi'));
END IF;
IF d_anfang IS NULL THEN
-- Datum auf Minimales Datum von ..._ZUB_DATEN_TMP_TAB setzen oder wenn
kein Datum vorhanden ist, alle Datums auffüllen.
SELECT min(to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') ),
max(to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') ) INTO d_anfang, d_ende FROM
zub_daten_tmp_tab;
END IF;
IF d_anfang != d_ende THEN
-- Nur ausführen, wenn ein Datum gefunden wurde.
--------------------------------------------------------------------------- EINTRAG DER FEHLENDEN DATUMS IN DIE FEHLERTABELLEN (FEHLER 1)
-- DBMS_SQL.CLOSE_CURSOR(c_dbms);
-- c_dbms := DBMS_SQL.OPEN_CURSOR;
n_exception_flag :=3000;
ausgabe := NULL;
<<fehlereintrag>>
FOR fehlt IN c_datum_fehlt LOOP
-d_fehlt := fehlt.ref_zeit;
IF datum_r_nr_in_tab(fehlt.ref_zeit, z.r_nr,
z.tab_name||'_FEHL_AUTO_TAB') = TRUE THEN
ausgabe := 'UPDATE ' || z.tab_name ||'_FEHL_AUTO_TAB SET
'|| z.sensor ||' = 1 WHERE datum = :fehl_ref_zeit AND r_nr = '||hk||z.r_nr||hk;
ELSE
ausgabe := 'INSERT INTO ' || z.tab_name ||'_FEHL_AUTO_TAB
(datum, r_nr,' || z.sensor ||') VALUES( :fehl_ref_zeit, '||hk||z.r_nr||hk||' , 1)';
END IF;
-- n_exception_flag :=3010;
DBMS_SQL.PARSE(c_dbms,ausgabe,DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(c_dbms, ':fehl_ref_zeit',fehlt.ref_zeit);
-DBMS_SQL.BIND_VARIABLE(c_dbms, ':z_r_nr',z.r_nr);
dummy := DBMS_SQL.EXECUTE(c_dbms);
-- Anzeige der fehlenden Datums
90
Anhang
-- DBMS_OUTPUT.PUT_LINE('-- Fehlendes Datum ' ||
to_char(fehlt.ref_zeit,'dd.mm.yyyy hh24:mi') || ' in '|| z.tab_name ||'_FEHL_AUTO_TAB
eingetragen');
END LOOP fehlereintrag;
COMMIT;
IF ausgabe IS NOT NULL THEN
ausgabe1 := ('-- Fehler 1: Es sind fehlende Datums gefunden
worden.');
ELSE
ausgabe1 := NULL;
END IF;
-- ENDE DATUM FEHLT
--------------------------------------------------------------------------- PRÜFEN OB ALLE WERTE VORHANDEN SIND (FEHLER 2)
-- Cursor zur Suche von NULL Werten.
n_exception_flag :=4000;
ausgabe := 'SELECT to_date(datum||uhrzeit,'||hk||'dd.mm.yyyy
hh24:mi'||hk||') FROM ZUB_DATEN_TMP_TAB WHERE to_date(datum||uhrzeit,'||hk||'dd.mm.yyyy
hh24:mi'||hk||') > :d_anfang AND '||z.hw_adr||' IS NULL';
-- DBMS_OUTPUT.PUT_LINE(ausgabe);
DBMS_SQL.PARSE(c_dbms_mess,ausgabe,DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN(c_dbms_mess, 1, d_mess);
DBMS_SQL.BIND_VARIABLE(c_dbms_mess, ':d_anfang',d_anfang);
--n_exception_flag :=4130;
dummy := DBMS_SQL.EXECUTE(c_dbms_mess);
-- Setzen der Default Ausgabe.
ausgabe := NULL;
-- '-- Keine fehlenden Messwerte';
<<fehlendeWerte>>
LOOP
n_exception_flag :=4200;
IF DBMS_SQL.FETCH_ROWS(c_dbms_mess) > 0 THEN
-- Datums heraussuchen.
DBMS_SQL.COLUMN_VALUE(c_dbms_mess, 1, d_mess);
-- Eintragen in die Fehlertabelle
IF datum_r_nr_in_tab(d_mess, z.r_nr,
z.tab_name||'_FEHL_AUTO_TAB') = TRUE THEN
ausgabe := 'UPDATE ' || z.tab_name
||'_FEHL_AUTO_TAB fehl SET '|| z.sensor ||' =2 WHERE datum = :v_d_mess AND r_nr =
:z_r_nr3';
ELSE
ausgabe := 'INSERT INTO ' || z.tab_name
||'_FEHL_AUTO_TAB(datum, r_nr ,'|| z.sensor ||') VALUES (:v_d_mess ,:z_r_nr3, 2)';
END IF;
DBMS_SQL.PARSE(c_dbms,ausgabe,DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(c_dbms, ':v_d_mess',d_mess);
DBMS_SQL.BIND_VARIABLE(c_dbms, ':z_r_nr3',z.r_nr);
dummy := DBMS_SQL.EXECUTE(c_dbms);
COMMIT;
ELSE
EXIT fehlendeWerte;
END IF;
END LOOP fehlendeWerte;
IF ausgabe IS NOT NULL THEN -- Es wurden fehlende Werte gefunden.
ausgabe2 := '-- Fehler 2: Mindestens ein Messwert ist nicht
vorhanden';
ELSE
ausgabe2 := NULL;
END IF;
COMMIT;
-- ENDE WERTE VORHANDEN
--------------------------------------------------------------------------- PRÜFEN DES MESSBEREICHS EINTRAG IN DIE FEHLERTABELLEN (FEHLER 3)
n_exception_flag :=5000;
ausgabe := 'SELECT to_date(datum||uhrzeit,'||hk||'dd.mm.yyyy
hh24:mi'||hk||') FROM ZUB_DATEN_TMP_TAB WHERE '|| z.hw_adr ||' NOT BETWEEN
'||z.minwert||' AND '||z.maxwert||' AND to_date(datum||uhrzeit,'||hk||'dd.mm.yyyy
hh24:mi'||hk||') > :d_anfang AND '||z.hw_adr||' IS NOT NULL';
--DBMS_OUTPUT.PUT_LINE(ausgabe);
-- n_exception_flag :=5100;
DBMS_SQL.PARSE(c_dbms_mess,ausgabe,DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN(c_dbms_mess, 1, d_mess);
DBMS_SQL.BIND_VARIABLE(c_dbms_mess, ':d_anfang',d_anfang);
dummy := DBMS_SQL.EXECUTE(c_dbms_mess);
91
Anhang
-- Setzen der Default Ausgabe.
ausgabe := NULL;
-- '-- Keine Messwerte ausserhalb des Messbereichs: Minimum '|| z.minwert
||' und Maximum '|| z.maxwert;
<<messbereich>>
LOOP
-- n_exception_flag :=5200;
IF DBMS_SQL.FETCH_ROWS(c_dbms_mess) > 0 THEN
-- Datums heraussuchen.
DBMS_SQL.COLUMN_VALUE(c_dbms_mess, 1, d_mess);
-- Eintragen in die Fehlertabelle
IF datum_r_nr_in_tab(d_mess, z.r_nr,
z.tab_name||'_FEHL_AUTO_TAB') = TRUE THEN
ausgabe := 'UPDATE ' || z.tab_name
||'_FEHL_AUTO_TAB fehl SET '|| z.sensor ||' =3 WHERE datum = :v_d_mess AND r_nr =
:z_r_nr4';
ELSE
ausgabe := 'INSERT INTO ' || z.tab_name
||'_FEHL_AUTO_TAB(datum, r_nr ,'|| z.sensor ||') VALUES (:v_d_mess ,:z_r_nr4, 3)';
END IF;
DBMS_SQL.PARSE(c_dbms,ausgabe,DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(c_dbms, ':v_d_mess',d_mess);
DBMS_SQL.BIND_VARIABLE(c_dbms, ':z_r_nr4',z.r_nr);
dummy := DBMS_SQL.EXECUTE(c_dbms);
-- Löschen der Werte aus ZUB_DATEN_TMP_TAB, die nicht im
Messbereich liegen.
-- Damit kann dann ZUB_DATEN_TMP_TAB in die ..._ROHKORR_TAB
kopiert werden.
--ausgabe := 'UPDATE zub_daten_tmp_tab SET '||z.hw_adr||' =
NULL WHERE to_date(datum||uhrzeit,'||hk||'dd.mm.yyyy hh24:mi'||hk||') = :v_d_mess';
--DBMS_SQL.PARSE(c_dbms1,ausgabe,DBMS_SQL.NATIVE);
--DBMS_SQL.BIND_VARIABLE(c_dbms1, ':v_d_mess',d_mess);
--dummy := DBMS_SQL.EXECUTE(c_dbms1);
--COMMIT;
ELSE
EXIT messbereich;
END IF;
END LOOP messbereich;
IF ausgabe IS NOT NULL THEN -- Es wurden Abweichungen im Messbereich
eingetragen
ausgabe3 := '-- Fehler 3: Mindestens ein Messwert ausserhalb des
Messbereichs';
ELSE
ausgabe3 := NULL;
END IF;
COMMIT;
-- ENDE MESSBEREICH
----------------------------------------------------------------------------------------- Fehlerausgabe
IF ausgabe1 IS NOT NULL OR ausgabe2 IS NOT NULL OR ausgabe3 IS NOT NULL
THEN
DBMS_OUTPUT.PUT_LINE('...........................................................
...................');
DBMS_OUTPUT.PUT_LINE('-- Tabelle: ' || z.tab_name || ' Raumnr.:
'|| z.r_nr || ' Sensor: ' || z.sensor ||' Minimum: '|| z.minwert ||' Maximum: '||
z.maxwert ||' Sauter: '||z.hw_adr);
DBMS_OUTPUT.PUT_LINE('-- Prüfen ab:
'||to_char(d_anfang,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE(ausgabe1);
DBMS_OUTPUT.PUT_LINE(ausgabe2);
DBMS_OUTPUT.PUT_LINE(ausgabe3);
--ELSE
-DBMS_OUTPUT.PUT_LINE('..................................................................
............');
--DBMS_OUTPUT.PUT_LINE('-- Tabelle: ' || z.tab_name || ' Raumnr.:
'|| z.r_nr || ' Sensor: ' || z.sensor ||' Minimum: '|| z.minwert ||' Maximum: '||
z.maxwert ||' Sauter: '||z.hw_adr);
--DBMS_OUTPUT.PUT_LINE('-- Prüfen ab:
'||to_char(d_anfang,'dd.mm.yyyy hh24:mi'));
--DBMS_OUTPUT.PUT_LINE('-- Es wurden keine Fehler gefunden');
END IF;
ELSE
-- Exception Aulösen
92
Anhang
n_exception_flag :=5000;
DBMS_OUTPUT.PUT_LINE('-- Tabelle: ' || z.tab_name || ' Raumnr.: '||
z.r_nr || ' Sensor: ' || z.sensor ||' Minimum: '|| z.minwert ||' Maximum: '|| z.maxwert
||' Sauter: '||z.hw_adr);
DBMS_OUTPUT.PUT_LINE('-- Es sind keine neueren Datums in ..._TMP_TAB als
in '||z.tab_name||'_ROH_TAB gefunden worden.');
DBMS_OUTPUT.PUT_LINE('-- Keine Fehlerprüfung durchgeführt.');
END IF;
END LOOP hauptschleife;
n_exception_flag :=10000;
-- Schliessen aller CURSOR
IF DBMS_SQL.IS_OPEN(c_dbms_mess) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_mess);
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms);
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms1) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms1);
END IF;
IF c_datum_fehlt%ISOPEN THEN
CLOSE c_datum_fehlt;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('EXCEPTION NO_DATA_FOUND in fehler_eintragen.sql ,
FLAG: '
|| n_exception_flag);
DBMS_OUTPUT.PUT_LINE('Wahrscheinlich ist ZUB_DATEN_TMP_TAB leer');
IF DBMS_SQL.IS_OPEN(c_dbms_mess) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_mess);
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms);
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms1) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms1);
END IF;
IF c_zuordnung%ISOPEN THEN
CLOSE c_zuordnung;
END IF;
IF c_datum_fehlt%ISOPEN THEN
CLOSE c_datum_fehlt;
END IF;
RAISE;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('EXCEPTION OTHERS in fehler_eintragen.sql ,
FLAG: ' ||
n_exception_flag);
IF DBMS_SQL.IS_OPEN(c_dbms_mess) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_mess);
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms);
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms1) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms1);
END IF;
IF c_zuordnung%ISOPEN THEN
CLOSE c_zuordnung;
END IF;
IF c_datum_fehlt%ISOPEN THEN
CLOSE c_datum_fehlt;
END IF;
RAISE;
END;
/
COMMIT;
93
Anhang
Skript 11: FUELLE_FEHL_INV_TAB.SQL
----------------------------------------------------------------------------------------- Datei: FUELLE_FEHL_INV_TAB.SQL
-- Erstellt: 11.12.2000
-------
Beschreibung:
Als erstes werden die Tabellen ..._FEHL_INV_TAB geleert und mit den
Datums und Raumnummern aus ...ROH_TAB gefüllt. (Die Datenspalten aus
..._FEHL_INV_TAB wurden mit DEFAULT 1 angelegt.)
Als zweites werden die Werte aus FEHL_TAB gelesen und die Werte auf NULL
zurückgesetzt die dort referenziert wurden.
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON
SET LINESIZE 255
SPOOL d:\zub_db\sql\meldungen\fuelle_fehl_inv_tab.txt
-- Leeren der Tabllen ...FEHL_INV_TAB
-- Füllen der Tabellen ...FEHL_INV_TAB mit den Datums und R_Nr aus ...ROH_TAB
DECLARE
c_dbms INTEGER;
dummy INTEGER;
ausgabe VARCHAR2(255);
CURSOR c_zu IS
SELECT DISTINCT UPPER(tab_name) tab_name from zuordnung
ORDER BY tab_name;
BEGIN
c_dbms := DBMS_SQL.OPEN_CURSOR;
DBMS_OUTPUT.ENABLE(1000000);
DBMS_OUTPUT.PUT_LINE('-- Füllen der Tabellen ..._FEHL_INV_TAB');
FOR z IN c_zu LOOP
-- Leeren
ausgabe := 'TRUNCATE TABLE '||z.tab_name||'_FEHL_INV_TAB';
DBMS_OUTPUT.PUT_LINE(ausgabe);
DBMS_SQL.PARSE(c_dbms,ausgabe,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms);
COMMIT;
-- Füllen
ausgabe := 'INSERT INTO '||z.tab_name||'_FEHL_INV_TAB(datum,r_nr) SELECT
datum,r_nr FROM '||z.tab_name||'_ROH_TAB';
DBMS_OUTPUT.PUT_LINE(ausgabe);
DBMS_SQL.PARSE(c_dbms,ausgabe,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms);
COMMIT;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(c_dbms);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('EXCEPTION OTHERS in fuelle_fehl_inv_tab.sql - Leeren und
Füllen der Tabellen ...FEHL_INV_TAB');
IF DBMS_SQL.IS_OPEN(c_dbms) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms);
END IF;
RAISE;
END;
/
-- UPDATEN der Tabellen ...FEHL_INV_TAB mit den eingetragenen Fehlern aus FEHL_TAB
DECLARE
c_dbms INTEGER;
dummy INTEGER;
ausgabe VARCHAR2(255);
CURSOR c_fehl_tab IS
SELECT * FROM FEHL_TAB
ORDER BY lfd_nr ASC;
94
Anhang
BEGIN
DBMS_OUTPUT.PUT_LINE('---------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('---------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('Updaten der Tabellen ..._FEHL_INV_TAB');
c_dbms := DBMS_SQL.OPEN_CURSOR;
FOR f IN c_fehl_tab LOOP
IF f.end_dat IS NULL THEN
f.end_dat := to_date('01.01.2100 00:00','dd.mm.yyyy hh24:mi');
END IF;
IF UPPER(f.sensor) ='ALLE' THEN
IF UPPER(f.r_nr)= 'ALLE' THEN
-- Raumnummer und Sensor -> 'ALLE'
ausgabe := 'DELETE FROM '||f.tab_name||'_FEHL_INV_TAB WHERE datum
BETWEEN :anf_dat AND :end_dat';
ELSE
-- Sensor -> ALLE
ausgabe := 'DELETE FROM '||f.tab_name||'_FEHL_INV_TAB WHERE
UPPER(r_nr) = '||CHR(39)||UPPER(f.r_nr)||CHR(39)|| ' AND datum BETWEEN :anf_dat AND
:end_dat';
END IF;
ELSE
IF UPPER(f.r_nr)= 'ALLE' THEN
-- Raumnummer -> 'ALLE'
ausgabe := 'UPDATE '||f.tab_name||'_FEHL_INV_TAB SET
'||f.sensor||'=NULL WHERE datum BETWEEN :anf_dat AND :end_dat';
ELSE
-- Spalte und Raumnummer definiert.
ausgabe := 'UPDATE '||f.tab_name||'_FEHL_INV_TAB SET
'||f.sensor||'=NULL WHERE UPPER(r_nr) = '||CHR(39)||UPPER(f.r_nr)||CHR(39)|| ' AND datum
BETWEEN :anf_dat AND :end_dat';
END IF;
END IF;
DBMS_OUTPUT.PUT_LINE('Lfd_Nr: '|| f.lfd_nr);
DBMS_OUTPUT.PUT_LINE(ausgabe);
DBMS_OUTPUT.PUT_LINE(' :Anf_Dat = '||to_char(f.anf_dat,'dd.mm.yyyy hh24:mi') ||'
:End_Dat = '||to_char(f.end_dat,'dd.mm.yyyy hh24:mi'));
DBMS_SQL.PARSE(c_dbms,ausgabe,DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(c_dbms,':anf_dat',f.anf_dat);
DBMS_SQL.BIND_VARIABLE(c_dbms,':end_dat',f.end_dat);
dummy := DBMS_SQL.EXECUTE(c_dbms);
COMMIT;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(c_dbms);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('EXCEPTION OTHERS in fuelle_fehl_inv_tab.sql - Updaten der
Tabellen ...FEHL_INV_TAB');
IF DBMS_SQL.IS_OPEN(c_dbms) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms);
END IF;
RAISE;
END;
/
SPOOL OFF
EXIT;
95
Anhang
Skript 12: FUNKTION_DATUM_R_NR_IN_TAB.SQL
----------------------------------------------------------------------------------------- Datei: FUNKTION_DATUM_R_NR_IN_TAB.SQL
-- Erstellt: 13.11.2000
-- Beschreibung:
-- Prüft, ob die das Datum mit der Raumnummer schon in einer Datenbanktabelle vorhanden
ist.
-- Liefert TRUE, falls es vorhanden ist; ansonsten FALSE
-- Änderungen:
-----------------------------------------------------------------------------------------CREATE OR REPLACE FUNCTION datum_r_nr_in_tab (dat DATE, raum IN VARCHAR2, tabelle IN
VARCHAR2) RETURN BOOLEAN IS
tab_datum
DATE;
--tmp_dat
DATE;
ist_da
NUMBER;
c_vorhanden
NUMBER;
hk
hochkomma.strich%TYPE;
raum_gross
VARCHAR2(30);
n_exception_flag
NUMBER(6) := 0;
--tabelle_gross
VARCHAR2(30);
BEGIN
SELECT strich INTO hk FROM hochkomma;
--tabelle := upper(tabelle);
--tmp_dat := to_date(to_char(dat,'dd.mm.yyyy hh24:mi'),'dd.mm.yyyy hh24:mi');
raum_gross := upper(raum);
c_vorhanden := DBMS_SQL.OPEN_CURSOR;
IF raum_gross ='ALLE' THEN
-- Diese Option wird für FORMS genutzt.
DBMS_SQL.PARSE(c_vorhanden,'SELECT datum FROM '||tabelle||' WHERE datum = :d_dat
', DBMS_SQL.NATIVE);
ELSE
DBMS_SQL.PARSE(c_vorhanden,'SELECT datum FROM '||tabelle||' WHERE datum = :d_dat
AND upper(r_nr)='||hk||raum_gross||hk, DBMS_SQL.NATIVE);
END IF;
DBMS_SQL.DEFINE_COLUMN(c_vorhanden, 1, tab_datum);
DBMS_SQL.BIND_VARIABLE(c_vorhanden, ':d_dat',dat);
--DBMS_SQL.BIND_VARIABLE(c_vorhanden, ':d_dat',tmp_dat);
--nvl(r_nr,'||hk||'9999'||hk||')
ist_da := DBMS_SQL.EXECUTE(c_vorhanden);
ist_da := DBMS_SQL.FETCH_ROWS(c_vorhanden);
-- DBMS_OUTPUT.PUT_LINE(ist_da);
DBMS_SQL.CLOSE_CURSOR(c_vorhanden);
IF ist_da != 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('EXCEPTION OTHERS in funktion_datum_r_nr_in_tab.sql ,
n_exception_flag);
IF DBMS_SQL.IS_OPEN(c_vorhanden) THEN
DBMS_SQL.CLOSE_CURSOR(c_vorhanden);
END IF;
RAISE;
END;
/
COMMIT;
FLAG: ' ||
96
Anhang
Skript 13: FUNKTION_FINDEANZAHL.SQL
----------------------------------------------------------------------------------------- Datei: FUNKTION_FINDEANZAHL.SQL
-- Erstellt: 07.11.2000
-- Beschreibung:
-- Findet die Anzahl der übergebenen 'chars' im Wort 'Wort'
----Änderungen:
------------------------------------------------------------------------------------------SET SERVEROUTPUT ON
CREATE OR REPLACE FUNCTION findeAnzahl (Wort IN VARCHAR2, chars IN VARCHAR2) RETURN
INTEGER IS
laengeWort
NUMBER(3);
tmp_laenge
NUMBER(3);
BEGIN
laengeWort := LENGTH(Wort);
tmp_laenge := LENGTH(REPLACE(Wort,chars,''));
RETURN laengeWort - tmp_laenge;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Fehler: Die Übergabeparameter für die Funktion find_ stimmen
nicht.');
RAISE;
END;
/
Skript 14: FUNKTION_SONDERZEICHEN.SQL
----------------------------------------------------------------------------------------- Datei: FUNKTION_SONDERZEICHEN.SQL
-- Erstellt: 07.12.2000
-- Beschreibung:
-- Wenn nur die Zeichen A-Z, 0-9 und ein _ im übergebenen String vorkommen,
-- wird TRUE zurückgegeben, ansonsten FALSE
---Änderungen:
------------------------------------------------------------------------------------------CREATE OR REPLACE FUNCTION sonderzeichen(str IN VARCHAR2) RETURN BOOLEAN IS
num NUMBER(2);
teilstr VARCHAR2(1);
BEGIN
num := LENGTH(str);
IF num >= 1 THEN
FOR i IN 1..num LOOP
teilstr := SUBSTR(str,i,1);
IF (ASCII(UPPER(teilstr))<65 OR ASCII(UPPER(teilstr))>90) AND
(ASCII(teilstr)<48 OR ASCII(teilstr)>57) AND ASCII(teilstr) != 95 THEN
-- str enthält andere Werte als von A-Z, 0-9 oder _
RETURN FALSE;
END IF;
END LOOP;
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
97
Anhang
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Unbehandelte Exception in Funktion sonderzeichen.');
RAISE;
END;
/
Skript 15: FUNKTION_SPALTE_VORHANDEN.SQL
----------------------------------------------------------------------------------------- Datei: FUNKTION_SPALTE_VORHANDEN.SQL
-- Erstellt: 04.11.2000
-- Beschreibung:
-- Prüft, ob die Spalte in einer Tabelle existiert und gibt Wert 'TRUE' zurück ansonsten
-- 'FALSE'
-- Änderungen:
-----------------------------------------------------------------------------------------CREATE OR REPLACE FUNCTION spalte_in_tabelle (tabelle IN VARCHAR2, spalte IN VARCHAR2)
RETURN BOOLEAN IS
ist_da
NUMBER;
c_vorhanden
NUMBER;
spalte_gross
VARCHAR2(30);
tabelle_gross VARCHAR2(30);
BEGIN
spalte_gross := upper(spalte);
tabelle_gross := upper(tabelle);
c_vorhanden := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(c_vorhanden,'SELECT column_name FROM user_tab_columns WHERE table_name =
:v_tmp_tab AND column_name= :v_spalte', DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(c_vorhanden,':v_spalte',spalte_gross);
DBMS_SQL.BIND_VARIABLE(c_vorhanden,':v_tmp_tab',tabelle_gross);
ist_da := DBMS_SQL.EXECUTE(c_vorhanden);
ist_da := DBMS_SQL.FETCH_ROWS(c_vorhanden);
-- DBMS_OUTPUT.PUT_LINE(ist_da);
DBMS_SQL.CLOSE_CURSOR(c_vorhanden);
IF ist_da != 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('EXCEPTION in Funktion
IF DBMS_SQL.IS_OPEN(c_vorhanden) THEN
DBMS_SQL.CLOSE_CURSOR(c_vorhanden);
END IF;
RAISE;
END;
/
COMMIT;
spalte_in_tabelle');
98
Anhang
Skript 16: FUNKTION_TAB_VORHANDEN.SQL
----------------------------------------------------------------------------------------- Datei: FUNKTION_TAB_VORHANDEN.SQL
-- Erstellt: 04.10.2000
-- Beschreibung:
-- Prüft, ob die Tabelle existiert und gibt Wert 'TRUE' zurück - ansonsten 'FALSE'
-- Änderungen:
-----------------------------------------------------------------------------------------CREATE OR REPLACE FUNCTION tab_vorhanden (tab IN VARCHAR2) RETURN BOOLEAN IS
ist_da
NUMBER;
c_vorhanden
NUMBER;
tab_gross
VARCHAR2(30);
BEGIN
tab_gross := upper(tab);
c_vorhanden := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(c_vorhanden,'SELECT table_name FROM user_tab_columns WHERE table_name =
:tabn', DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(c_vorhanden,':tabn',tab_gross);
ist_da := DBMS_SQL.EXECUTE(c_vorhanden);
ist_da := DBMS_SQL.FETCH_ROWS(c_vorhanden);
DBMS_SQL.CLOSE_CURSOR(c_vorhanden);
IF ist_da != 0 THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END IF;
EXCEPTION
WHEN OTHERS THEN
IF DBMS_SQL.IS_OPEN(c_vorhanden) THEN
DBMS_SQL.CLOSE_CURSOR(c_vorhanden);
END IF;
RAISE;
END;
/
COMMIT;
99
Anhang
Skript 17: FUNTKION_ZUORDNUNG_PRUEFEN.SQL
----------------------------------------------------------------------------------------- Datei: FUNKTION_ZUORDNUNG_PRUEFEN.SQL
-- Erstellt: 06.11.2000
-- Beschreibung:
-- Diese Funktion prüft die Tabellen ZUORDNUNG und ZUB_DATEN_TMP_TAB auf konsistenz.
-- Wenn der Funktion "ANLEGEN" übergeben wird. wird Punkt 4 (s.u.) nicht geprüft.
-- 1) Prüfung der Tabelle Zuordnung, ob HW_ADR mehrfach vorkommen.
-- 2) Prüfung, ob Sensoren (Spalte SENSOR) in ZUORDNUNG konsistent sind -also keine Sensoren und gleichzeitig Raumnummern bei einer Tabelle Tab_Name
-doppelt in ZUORDNUNG vorkommen!
-- 3) Prüfung, ob alle Spalten aus ZUB_DATEN_TMP_TAB in ZUORDNUNG vorhanden sind.
-- 4) Prüfung, ob alle Spalten aus ZUORDNUNG in ZUB_DATEN_TMP_TAB vorhanden sind.
-(Bei Aufruf der Funktion mit dem Parameter "ANLEGEN" wird dieser Punkt nicht
-geprüft).
-- 5) Prüfen, nur Zeichen 0-9,A-Z und _ in ZUORDNUNG vorkommen.
-- Returniert wird das sogenannte "flag_fehler_zuordnung". Dieser
"flag_fehler_zuordnung"
-- wird auch in die Tabelle ZUORDNUNG_GEPRUEFT eingetragen.
-- Es werden hier 4 Fehler behandelt die in verschiedenen kombinationen auftreten
können.
-- Dazu werden der flag_fehler_zuordnung mit 4 Bit codiert. Es werden die Zahlen 0-15
-- returniert.
-- Bit 1: Punkt 1) HW_ADR kommen mehrmals vor in ZUORDNUNG (keine weitere Bearbeitung
-möglich)
-- Bit 2: Punkt 2) Raumnummer (R_Nr) und Sensorname (SENSOR) kommen merhmals vor in
-ZUORDNUNG (Fehler)
-- Bit 3: Punkt 3) Die Spalte XXX aus ZUB_DATEN_TMP_TAB existiert nicht in ZUORDNUNG
-(Warnung oder Fehler)
-- Bit 4: Punkt 4) Die Spalte XXX aus ZUORDNUNG existiert nicht in ZUB_DATEN_TMP_TAB
-(Fehler)
-- Bit 5: Punkt 5) Syntax
--Änderungen:
------------------------------------------------------------------------------------------SET SERVEROUTPUT ON
--DECLARE
CREATE OR REPLACE FUNCTION zuordnung_pruefen (flag_anlegen IN VARCHAR2) RETURN INTEGER
IS
ausgabe
VARCHAR2(300) := NULL;
ausgabe1
VARCHAR2(300) := NULL;
ausgabe2
VARCHAR2(1000) := NULL;
---------------------------------------------------------------------- CURSOR zum Vergleichen von ZUB_DATEN_TMP_TAB und ZUORDNUNG
CURSOR c1 IS
SELECT column_name FROM user_tab_columns WHERE table_name = 'ZUB_DATEN_TMP_TAB'
AND column_name NOT IN ('DATUM', 'UHRZEIT')
MINUS
SELECT hw_adr FROM ZUORDNUNG;
CURSOR c1_inv IS
SELECT hw_adr FROM ZUORDNUNG
MINUS
SELECT column_name FROM user_tab_columns WHERE table_name = 'ZUB_DATEN_TMP_TAB'
AND column_name NOT IN ('DATUM', 'UHRZEIT');
----------------------------------------------------------------------------------------- Variable und Cursor zum internen Prüfen von ZUORDNUNG
-- 1) Sind HW_ADR doppelt? -> Keine weitere Bearbeitung mehr möglich, da die Werte nicht
-eindeutig sind!
-- 2) Sind Raumnummern und gleichzeitig Sensornamen identisch? -> Raumnummern werden
-automatisch mit Indizies versehen.
n_exception_flag
NUMBER(6);
spalte_vorh
user_tab_columns.column_name%TYPE; -- Zweite Variable für
'spalte'
tmp_tab_name
zuordnung.tab_name%TYPE; -- Temporärer Speicher für aktuellen
-- Tabellennamen (DBMS_SQL Funktion)
flag_fehler_zuordnung
NUMBER(2) := 0;
100
Anhang
tmp_flag_fehler_zuordnung
i
erster_lauf
syntax_ok
BOOLEAN;
NUMBER(2) := 0;
NUMBER(2) := 0;
BOOLEAN
:= TRUE;
CURSOR c_tab_name
IS
SELECT DISTINCT UPPER(tab_name) tab_name from zuordnung
ORDER BY UPPER(tab_name);
-- Prüfen, ob <Tab_Name> mehrfach die gleichen Raumnummern und Sensoren enthält
CURSOR c_finde_doppelte_eintraege IS
SELECT UPPER(z.r_nr) r_nr, UPPER(z.sensor) sensor, UPPER(z.hw_adr) hw_adr FROM zuordnung
z
WHERE 1<(SELECT count(z1.r_nr) FROM zuordnung z1
WHERE UPPER(z.r_nr) = UPPER(z1.r_nr)
AND UPPER(z.sensor) = UPPER(z1.sensor)
AND UPPER(z1.tab_name) = UPPER(tmp_tab_name))
AND UPPER(z.tab_name) = UPPER(tmp_tab_name)
ORDER BY UPPER(z.r_nr), UPPER(z.sensor) ASC;
-- Prüfen, ob Zuordnung mehrfach die gleichen HW_ADR enthält
CURSOR c_hw_adr_doppelt IS
SELECT UPPER(z.r_nr) r_nr, UPPER(z.sensor) sensor, UPPER(z.hw_adr) hw_adr,
UPPER(z.tab_name) tab_name FROM zuordnung z
WHERE 1<(SELECT count(z1.hw_adr) FROM zuordnung z1
WHERE UPPER(z.hw_adr) = UPPER(z1.hw_adr));
-- Auf Sonderzeichen Prüfen
CURSOR c_sonder IS
SELECT * FROM ZUORDNUNG
ORDER BY tab_name, sensor, r_nr;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------BEGIN
DBMS_OUTPUT.ENABLE(1000000);
UPDATE zuordnung_geprueft SET flag = 0;
in der Tabelle
-- Das Fehlerflag für die Prüfung von ZUORDNUNG
-ZUORDNUNG_GEPRUEFT zurücksetzen.
COMMIT;
-- Prüfen von ZUORDNUNG
-------------------------------------------------------------------------------------- Punkt1) PRÜFEN DOPPELTER HW_ADR
-- Gibt es HW_ADR die in Zuordnung mehrmals auftreten? Wenn ja, werden
-- keine Tabellen angelegt oder verändert!!!!
n_exception_flag := 1000;
erster_lauf := TRUE;
FOR doppelt IN c_hw_adr_doppelt LOOP
IF erster_lauf = TRUE THEN
erster_lauf := FALSE;
flag_fehler_zuordnung :=1;
DBMS_OUTPUT.PUT_LINE('----------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Pruefen der HW_ADR');
DBMS_OUTPUT.PUT_LINE('-- Fehler: Folgende HW_ADR in Zuordnung kommen
mehrmals vor:');
DBMS_OUTPUT.PUT_LINE('-Korrigieren Sie den Fehler mit dem
ISP Listen von Sauter.');
DBMS_OUTPUT.PUT_LINE('-Ansonsten besteht die hohe
Wahrscheinlichkeit eines Fehlers');
DBMS_OUTPUT.PUT_LINE('-in der weiteren Verarbeitung!!!');
-DBMS_OUTPUT.PUT_LINE('-Es werden keine Tabellen angelegt
oder verändert!!!');
END IF;
DBMS_OUTPUT.PUT_LINE('-- Doppelt: '|| doppelt.hw_adr ||' Tabelle: '||
doppelt.tab_name||' Raumnummer: '|| doppelt.r_nr ||' sensor: '|| doppelt.sensor);
END LOOP;
erster_lauf := TRUE;
----------------------------------------------------------------------------------------- Punkt 2) PRÜFEN GLEICHER RAUMNUMMER UND SENSOR
-- Werden gleiche gefunden wird der Sensor indiziert.
n_exception_flag := 2000;
<<tabellenname>>
FOR tab IN c_tab_name LOOP -- Tabellennamen selektieren
101
Anhang
i := 0; -- Indx wieder auf 0 setzen.
tmp_tab_name := tab.tab_name;
ausgabe := NULL;
ausgabe1 := NULL;
ausgabe2 := NULL;
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Pruefen und indizieren gleicher Raumnummer (R_NR) und
Sensor (SENSOR) für Tabellenname '||tmp_tab_name|| ' in ZUORDNUNG.');
<<doppelteWerte>>
FOR doppelt IN c_finde_doppelte_eintraege LOOP -- doppelte Einträge finden.
i := i +1;
IF i <= 12 THEN -- Ausgabe wird unterteilt, falls zuviele gleiche HW_ADR
auftreten.
ausgabe := ausgabe ||' '||doppelt.hw_adr; -- Sammeln der HW_ADR
zur Ausgabe.
ELSIF i > 12 AND i <=25 THEN
ausgabe1 := ausgabe1 ||' '||doppelt.hw_adr;
ELSE
ausgabe2 := ausgabe2 ||' '||doppelt.hw_adr;
END IF;
DBMS_OUTPUT.PUT_LINE('-- Doppelte Raumnummer '|| doppelt.r_nr ||' und
Sensor '||doppelt.sensor||' bei HW_ADR: '|| doppelt.hw_adr);
COMMIT;
tmp_flag_fehler_zuordnung := 2;
END LOOP doppelteWerte;
IF i != 0 THEN -- Alle HW_ADR ausgeben, in denen Raumnummer und Sensor gleich
sind.
DBMS_OUTPUT.PUT_LINE('-Doppelt in: '|| ausgabe);
DBMS_OUTPUT.PUT_LINE('-'|| ausgabe1);
DBMS_OUTPUT.PUT_LINE('-'|| ausgabe2);
END IF;
END LOOP tabellenname;
IF tmp_flag_fehler_zuordnung = 2 THEN
DBMS_OUTPUT.PUT_LINE('-----------------');
DBMS_OUTPUT.PUT_LINE('--');
DBMS_OUTPUT.PUT_LINE('-- FEHLER: ');
DBMS_OUTPUT.PUT_LINE('-- Es wurden mehrfach vorkommende Raumnummern und Sensoren
gefunden.');
DBMS_OUTPUT.PUT_LINE('-- Ändern Sie ZUORDNUNG und führen Sie das Skript erneut
aus.');
DBMS_OUTPUT.PUT_LINE('-- Führen Sie die Änderungen in Ihrer Dokumentation nach.
');
DBMS_OUTPUT.PUT_LINE('----------------------------------------------------------------');
END IF;
erster_lauf := TRUE;
flag_fehler_zuordnung := flag_fehler_zuordnung + tmp_flag_fehler_zuordnung; -- Das
flag_fehler_zuordnung ist jetzt 2 oder 3 (1+2)
tmp_flag_fehler_zuordnung := 0;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Punkt 3) Ableich der Tabellen ZUB_DATEN_TMP_TAB und ZUORDNUNG.
n_exception_flag := 3000;
FOR spalte1 IN c1 LOOP
IF erster_lauf =TRUE THEN
DBMS_OUTPUT.PUT_LINE('----------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Abgleichen von ZUB_DATEN_TMP_TAB mit
ZUORDNUNG.');
DBMS_OUTPUT.PUT_LINE('--');
erster_lauf := FALSE;
END IF;
tmp_flag_fehler_zuordnung := 4;
ausgabe := spalte1.column_name;
DBMS_OUTPUT.PUT_LINE('--');
DBMS_OUTPUT.PUT_LINE('-- Fehler: Die Spalte '|| ausgabe ||' aus ZUB_DATEN_TMP_TAB
existiert nicht in ZUORDNUNG.');
END LOOP;
IF tmp_flag_fehler_zuordnung = 4 THEN
DBMS_OUTPUT.PUT_LINE('--');
102
Anhang
DBMS_OUTPUT.PUT_LINE('-Prüfen Sie ZUORDNUNG, ob beim Anlegen eine
PRIMARY KEY Verletzung');
DBMS_OUTPUT.PUT_LINE('-auftrat oder die Spalte schlicht vergessen
wurde oder ob die Daten');
DBMS_OUTPUT.PUT_LINE('-nicht aufgenommen werden sollen.');
DBMS_OUTPUT.PUT_LINE('-Im letzteren Fall tragen Sie die Daten
trotzdem in ZUORDNUNG ein und verwenden');
DBMS_OUTPUT.PUT_LINE('-Sie eine neue Tabelle, damit keine Daten
verloren gehen.');
END IF;
erster_lauf := TRUE;
flag_fehler_zuordnung := flag_fehler_zuordnung + tmp_flag_fehler_zuordnung; -flag_fehler_zuordnung ist jetzt 4,5,6,7
------------------------------------- Punkt 4)
n_exception_flag := 4000;
tmp_flag_fehler_zuordnung := 0;
IF UPPER(REPLACE(flag_anlegen,' ','')) != 'ANLEGEN' THEN
-- In diesem Fall diese
Fehlerprüfung überspringen.
FOR spalte IN c1_inv LOOP
IF erster_lauf =TRUE THEN
DBMS_OUTPUT.PUT_LINE('-...........................................');
DBMS_OUTPUT.PUT_LINE('----------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Abgleichen von ZUORDNUNG mit
ZUB_DATEN_TMP_TAB.');
DBMS_OUTPUT.PUT_LINE('--');
erster_lauf := FALSE;
END IF;
tmp_flag_fehler_zuordnung := 8;
ausgabe := spalte.hw_adr;
DBMS_OUTPUT.PUT_LINE('--');
DBMS_OUTPUT.PUT_LINE('-- Fehler: Die Spalte '|| ausgabe ||' aus ZUORDNUNG
existiert nicht in ZUB_DATEN_TMP_TAB (Sauter Daten).');
END LOOP;
erster_lauf := TRUE;
IF tmp_flag_fehler_zuordnung = 8 THEN
DBMS_OUTPUT.PUT_LINE('--');
DBMS_OUTPUT.PUT_LINE('-Prüfen Sie nach den ISP
(Informationsschwerpunkt (Tabellen)), ob dieser Datenpunkt ');
DBMS_OUTPUT.PUT_LINE('-zur Messswerterfassung vorgesehen ist,
wenn ja: ');
DBMS_OUTPUT.PUT_LINE('-Wenden Sie sich an die verantwortliche
Firma für die Datenmessungen im ZUB, ');
DBMS_OUTPUT.PUT_LINE('-ob dieser Messpunkt zur Aufnahme
vorgesehen ist');
DBMS_OUTPUT.PUT_LINE('-wenn nein, löschen Sie den Messpunkt in
ZUORDNUNG!!!.');
DBMS_OUTPUT.PUT_LINE('-Der Messpunkt wird in der zukünfitgen
Verarbeitung ignoriert !!!!!!!!!.');
DBMS_OUTPUT.PUT_LINE('----------------------------------------------------------------');
END IF;
END IF;
flag_fehler_zuordnung := flag_fehler_zuordnung + tmp_flag_fehler_zuordnung;
tmp_flag_fehler_zuordnung := 0;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Punkt 5) Prüfen auf Sonderzeichen ZUORDNUNG.
i := 0;
DBMS_OUTPUT.PUT_LINE('----------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Prüfen der Syntax von ZUORDNUNG .');
DBMS_OUTPUT.PUT_LINE('--');
FOR sonder IN c_sonder LOOP
syntax_ok :=
sonderzeichen(sonder.hw_adr||sonder.tab_name||sonder.sensor||sonder.r_nr||sonder.format)
;
IF syntax_ok = FALSE THEN
i := i +1;
103
Anhang
DBMS_OUTPUT.PUT_LINE('-- Sonderzeichen in Hw_Adr '||sonder.hw_adr||'
Tab_Name
'||sonder.tab_name||'
Sensor '||sonder.sensor||'
R_Nr '||sonder.r_nr||'
Format
'||sonder.format||' gefunden.');
END IF;
END LOOP;
IF i > 0 THEN
tmp_flag_fehler_zuordnung := 32;
DBMS_OUTPUT.PUT_LINE('-- FEHLER: Es sind mindestens '||i||' Sonderzeichen in
ZUORDNUNG gefunden worden.');
DBMS_OUTPUT.PUT_LINE('-- Ändern Sie ZUORDNUNG und führen Sie das Skript erneut
aus.');
ELSE
DBMS_OUTPUT.PUT_LINE('-- Keine Syntaxfehler gefunden.');
END IF;
flag_fehler_zuordnung := flag_fehler_zuordnung + tmp_flag_fehler_zuordnung;
tmp_flag_fehler_zuordnung := 0;
UPDATE zuordnung_geprueft SET flag = flag_fehler_zuordnung;
COMMIT;
DBMS_OUTPUT.PUT_LINE('----------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Die Fehleranzeige ist: ' ||flag_fehler_zuordnung);
DBMS_OUTPUT.PUT_LINE('-- ENDE von zuordnung_pruefen.');
DBMS_OUTPUT.PUT_LINE('----------------------------------------------------------------');
RETURN flag_fehler_zuordnung;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler: Exception OTHERS in
funktion_zuordnung_pruefen.sql. FLAG: '||n_exception_flag);
IF c_tab_name%ISOPEN THEN
CLOSE c_tab_name;
END IF;
IF c_finde_doppelte_eintraege%ISOPEN THEN
CLOSE c_finde_doppelte_eintraege;
END IF;
IF c_hw_adr_doppelt%ISOPEN THEN
CLOSE c_hw_adr_doppelt;
END IF;
IF c1%ISOPEN THEN
CLOSE c1;
END IF;
IF c1_inv%ISOPEN THEN
CLOSE c1_inv;
END IF;
RAISE;
END;
/
COMMIT;
--select table_name from user_tables;
--desc Klima;
--desc StdR;
104
Anhang
Skript 18: INITUMGEBUNGSTABELLEN.SQL
----------------------------------------------------------------------------------------- Datei: INITUMGEBUNGSTABELLEN.SQL
-- Erstellt: 04.09.2000
-- Beschreibung:
-- Initialisieren der ZUB Datenbank für die erste Inbetriebnahme
-- - Füllen der Tabelle ANHANG, die die Anhängsel für die Datentabellen enthält.
-- - Anfangswert für ZEITTAB festlegen.
-- - Standardfehler für die automatische Fehlererkennung festlegen.
-- - Ein ' - das ist CHR(39) in ASCII - in die Tabelle HOCHKOMMA eintragen.
-- - Das Prüfflag für ZUORDNUNG auf 0 (entspricht -> keine Fehler) setzen.
-- Änderungen:
------------------------------------------------------------------------------------------- Tabelle Anhang initialisieren.
-- !!! DIESE TABELLE DARF NICHT GEÄNDERT WERDEN !!!
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
Anhang
Anhang
Anhang
Anhang
Anhang
Anhang
Anhang
Anhang
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
('_TMP_TAB');
('_FEHL_AUTO_TAB');
('_FEHL_INV_TAB');
('_ROH_TAB');
('_ROHKORR_TAB');
('_TAG_TAB');
('_MONAT_TAB');
('_JAHR_TAB');
COMMIT;
-- Jahres und Monatsmittelwert werden eingetragen.
--TRUNCATE TABLE Zeittab_fuellen;
INSERT INTO Zeittab_fuellen VALUES (TRUNC(SYSDATE,'YYYY'));
COMMIT;
-- Fehlercode festlegen.
INSERT INTO FEHLER_CODE VALUES (1,'Datum nicht vorhanden.');
INSERT INTO FEHLER_CODE VALUES (2,'Wert ist nicht vorhanden (ev. Sensorausfall).');
INSERT INTO FEHLER_CODE VALUES (3,'Wert liegt nicht im Messbereich.');
COMMIT;
-- Hochkomma eintragen (Es wird ein ' eingetragen, wenn ASCII Format vorhanden ist
-- Ist die Codepage 500 wird das EBCDIC Format verwendet und es muss CHR(125) eingesetzt
werden.
TRUNCATE TABLE HOCHKOMMA;
INSERT INTO HOCHKOMMA VALUES (CHR(39));
-- Hier wird ein Flag eingetragen, welche Fehler die Tabelle ZUORDNUNG enthält.
-- Bei einer 0 ist ZUORDNUNG o.k.
TRUNCATE TABLE ZUORDNUNG_GEPRUEFT;
INSERT INTO ZUORDNUNG_GEPRUEFT VALUES(0);
105
Anhang
Skript 19: PROZEDUR_DATUM_VERBESSERN.SQL
----------------------------------------------------------------------------------------- Datei: PROZEDUR_DATUM_VERBESSERN.SQL
-- Erstellt: 06.11.2000
-- Beschreibung:
-- Verbesserung falscher Datums ZUB_DATEN_TMP_TAB. Ein falsches Datum ist eine
Abweichung
-- von den Datumsintervallen in der Tabelle ZEITTAB. Das falsche Datum in
ZUB_DATEN_TMP_TAB
-- wird automatisch verbessert und entsrpechend weiter verarbeitet vom aufrufenden
Skript.
-- Vorteil:
Die Funktion wählt automatisch das erste Datum aus, das im Intervall
+/-6min.nicht existiert. D.h.
-die Abweichung eines Datums kann auch grösser sein als 3 min.
-(die halbe Intervallzeit).
-- Schwäche:
Fehlt ein Datum (z.B.: 00:06) und das nächste ist falsch (z.B.:00:11),
-dann setzt die Funktion das Datum auf 00:06 und nicht - was eventuell
-richtig ist auf 00:12.
-- Bem.:
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON;
CREATE OR REPLACE PROCEDURE datum_verbessern IS
v2_dummy
VARCHAR2(10);
CURSOR c_datum IS SELECT to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') from
zub_daten_tmp_tab;
-- DBMS_SQL
dummy
INTEGER;
c_dbms_hw_adr
INTEGER;
-- VARIABLE FÜR DIE FEHLENDEN TABELLEN
strout
VARCHAR2(200);
ch_sensor
zuordnung.sensor%TYPE;
ch_tab_name
zuordnung.tab_name%TYPE;
ch_r_nr zuordnung.r_nr%TYPE;
-- CURSOR UND VARIABLE FÜR DIE VERBESSERUNG FALSCHER DATUMS
d_anfang
DATE;
d_ende
DATE;
d_falsch
DATE;
d_nahes_datum DATE;
d_erstes_ungueltiges_datum
DATE;
datumsfehler_flag
NUMBER(1) :=0;
-- CUROSR findet die falschen Datums mit falschen Zeiten
CURSOR c_datum_falsch IS
SELECT to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') from zub_daten_tmp_tab
MINUS
SELECT ref_zeit FROM zeittab
WHERE ref_zeit BETWEEN d_anfang AND d_ende;
-- Cursor findet gültige Datumwerte im Bereich d_falsch +/- 6 Minuten.
-- d_falsch wird im Cursor c_datum falsch selektiert.
-- Das Datum aus ZUB_DATEN_TMP_TAB wird auf das erste ungültige Datum gesetzt.
CURSOR c_finde_nahes_datum IS
SELECT ref_zeit FROM zeittab
WHERE ref_zeit BETWEEN (d_falsch - 6/(24*60)) AND (d_falsch + 6/(24*60))
ORDER BY ref_zeit ASC;
-- Wenn ein nahes Datum vorhanden ist und dieses Datum NICHT in TMP_DATNE existiert,
-- wird dieses Datum übernommen, andernfalls wird das nächste überprüft.
CURSOR c_erstes_ungueltiges_datum IS
SELECT to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') FROM zub_daten_tmp_tab
WHERE to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') = d_nahes_datum;
----------------------------------------------------------------------------------------
106
Anhang
BEGIN
-- VERBESSERN DES DATUMS IN ZUB_DATEN_TMP_TAB
c_dbms_hw_adr := DBMS_SQL.OPEN_CURSOR;
-- NULL Datums löschen.
DELETE FROM zub_daten_tmp_tab WHERE datum IS NULL OR uhrzeit IS NULL;
COMMIT;
-- Ältestes und jüngstes Datum speichern.
SELECT min(to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi')),
max(to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi')) INTO d_anfang, d_ende FROM
zub_daten_tmp_tab;
-- Falsche Datums korrigieren
OPEN c_datum_falsch;
<<falschesDatum>>
LOOP
-- d_falsch enthält die falschen Datums oder
-- wenn alle Datums richtig sind, wird die Schleife unmittelbar verlassen.
FETCH c_datum_falsch INTO d_falsch;
EXIT falschesDatum WHEN c_datum_falsch%NOTFOUND;
-DBMS_OUTPUT.PUT_LINE('-- Tabelle: ZUB_DATEN_TMP_TAB; Falsches Datum: ' ||
to_char(d_falsch,'dd.mm hh24:mi'));
OPEN c_finde_nahes_datum;
<<ungueltigesDatum>>
LOOP
-- Suchen des ersten ungültigen Datums
FETCH c_finde_nahes_datum INTO d_nahes_datum;
IF c_finde_nahes_datum%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('-- Kein nahes Datum gefunden. Falsches
Datum: ' || to_char(d_falsch,'dd.mm hh24:mi'));
EXIT ungueltigesDatum WHEN c_finde_nahes_datum%NOTFOUND;
ELSE -- tmp_hw_adr nach dem ersten ungültigen Wert durchsuchen.
OPEN c_erstes_ungueltiges_datum;
FETCH c_erstes_ungueltiges_datum INTO d_erstes_ungueltiges_datum;
IF c_erstes_ungueltiges_datum%NOTFOUND THEN
UPDATE zub_daten_tmp_tab SET datum =
to_char(d_nahes_datum,'dd.mm.yyyy') ,uhrzeit = to_char(d_nahes_datum,'hh24:mi') WHERE
to_date(datum||uhrzeit,'dd.mm.yyyy hh24:mi') = d_falsch;
-- ZUM direkten lesen des falschen Datums
DBMS_OUTPUT.PUT_LINE('-- Tabelle ZUB_DATEN_TMP_TAB;
Falsches Datum: ' || to_char(d_falsch,'dd.mm hh24:mi') ||' Datum geupdated ' ||
to_char(d_nahes_datum,'dd.mm hh24:mi'));
-- Fehlerflag setzen
datumsfehler_flag := 1;
COMMIT;
EXIT ungueltigesDatum WHEN
c_erstes_ungueltiges_datum%NOTFOUND;
END IF;
END IF;
CLOSE c_erstes_ungueltiges_datum;
COMMIT;
END LOOP ungueltigesDatum;
IF c_finde_nahes_datum%ISOPEN THEN
CLOSE c_finde_nahes_datum;
END IF;
IF c_erstes_ungueltiges_datum%ISOPEN THEN
CLOSE c_erstes_ungueltiges_datum;
END IF;
-DBMS_OUTPUT.PUT_LINE('-- Datum zwischen ' || to_char(d_falsch 6/(24*60),'dd.mm.yy hh24:mi') ||' UND '|| to_char(d_falsch + 6/(24*60),'dd.mm.yy
hh24:mi'));
DBMS_OUTPUT.PUT_LINE('-- Falsches Datum: ' || to_char(d_falsch,'dd.mm hh24:mi')
|| ' Nahes Datum: ' || to_char(d_nahes_datum,'dd.mm hh24:mi'));
d_nahes_datum := NULL;
COMMIT;
END LOOP falschesDatum;
IF datumsfehler_flag = 1 THEN
DBMS_OUTPUT.PUT_LINE('-- Warnung: In der Tabelle TMP_DATUM sind falsche Datums
verbessert worden.');
END IF;
IF c_finde_nahes_datum%ISOPEN THEN
CLOSE c_finde_nahes_datum;
END IF;
CLOSE c_datum_falsch;
COMMIT;
IF c_datum%ISOPEN THEN
CLOSE c_datum;
107
Anhang
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms_hw_adr) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_hw_adr);
END IF;
---------------------------------------------------------------------------------------EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('-- Exception OTHERS: Es sind keine Daten in
ZUB_DATEN_TMP_TAB.');
DBMS_OUTPUT.PUT_LINE('-- Diese Prozedur wird in Ablaufstrg_taeglich.sql
verwendet.');
IF c_datum%ISOPEN THEN
CLOSE c_datum;
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms_hw_adr) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_hw_adr);
END IF;
RAISE;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Exception OTHERS: Es sind keine Daten in den kopierten
dBase Tabellen (kopie_tmp_hw_adr.sql).');
DBMS_OUTPUT.PUT_LINE('-- Diese Prozedur wird in rohdaten_messbereich.sql
verwendet.');
IF c_datum%ISOPEN THEN
CLOSE c_datum;
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms_hw_adr) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms_hw_adr);
END IF;
RAISE;
END;
/
COMMIT;
108
Anhang
Skript 20: PROZEDUR_DB_SPALTEN_ANLEGEN.SQL
----------------------------------------------------------------------------------------- Datei: PROZEDUR_DB_SPALTEN_ANLEGEN.SQL
-- Erstellt: 24.11.2000
-----
Beschreibung:
Prodzedur fügt eine Spalte in eine Datentabelle ein.
Dabei wird unterschieden, ob es sich um eine Fehlertabelle
oder um eine Messdatentabelle handelt.
--Änderungen:
------------------------------------------------------------------------------------------CREATE OR REPLACE PROCEDURE db_spalte_anlegen(tab_name IN VARCHAR2, sensor IN VARCHAR2,
format IN VARCHAR2) AS
tmp_name
zuordnung.tab_name%TYPE;
b
BOOLEAN;
c_dbms
INTEGER;
dummy
INTEGER;
n_exception_flag NUMBER(6);
binaer
VARCHAR2(20) := ' NUMBER(1)';
analog
VARCHAR2(20) := ' NUMBER(5,2)';
fehler_format
VARCHAR2(20) := ' NUMBER(2)';
num_format
VARCHAR2(30);
BEGIN
n_exception_flag := 0;
c_dbms := DBMS_SQL.OPEN_CURSOR;
-- Übernehmen des Formates!
IF SUBSTR(UPPER(format),1,2) = 'B' THEN
-- Binärwert
num_format :=binaer;
ELSIF SUBSTR(UPPER(format),1,2) = 'A' THEN
-- Analogwert
num_format := analog;
ELSE
num_format := 'UNGUELTIG';
END IF;
n_exception_flag := 100;
/*
DBMS_OUTPUT.PUT_LINE(tab_name||' '||sensor||' '||format);
b := spalte_in_tabelle(tab_name,sensor);
IF b = TRUE THEN
DBMS_OUTPUT.PUT_LINE('Fehler Spalte in Tabelle : JA');
ELSE
DBMS_OUTPUT.PUT_LINE('I.O. Spalte in Tabelle : NEIN');
END IF;
b := tab_vorhanden(tab_name) ;
IF b = FALSE THEN
DBMS_OUTPUT.PUT_LINE('Fehler Tabelle vorhanden: NEIN');
ELSE
DBMS_OUTPUT.PUT_LINE('I.O. Tabelle vorhanden: JA');
END IF;
DBMS_OUTPUT.PUT_LINE('Format: '||num_format);
n_exception_flag := 200;
*/
IF num_format = 'UNGUELTIG' OR spalte_in_tabelle(tab_name,sensor) = TRUE OR
tab_vorhanden(tab_name) = FALSE THEN
-- FEHLER
n_exception_flag := 300;
raise_application_error(-20101, 'Fehler: Entweder Format ungültig, Spalte ist
schon in Tabelle oder Tabelle nicht vorhanden.');
ELSE
n_exception_flag := 1000;
IF INSTR(tab_name,'_FEHL') = 0 THEN
109
Anhang
n_exception_flag := 1100;
-- Einfügen der Spalte 'spalte' in die Tabelle 'tmp_name'
DBMS_SQL.PARSE(c_dbms,'ALTER TABLE ' || tab_name || ' ADD (' || sensor ||
num_format || ')',DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms);
ELSIF INSTR(tab_name,'_FEHL_AUTO_TAB') != 0 THEN
n_exception_flag := 1200;
DBMS_SQL.PARSE(c_dbms,'ALTER TABLE ' || tab_name || ' ADD (' ||
sensor || fehler_format || ')',DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms);
ELSIF INSTR(tab_name,'_FEHL_INV_TAB') != 0 THEN
n_exception_flag := 1300;
-- Fehlertabellen mit Splaten im Format Number(2) anlegen
n_exception_flag := 1100;
DBMS_SQL.PARSE(c_dbms,'ALTER TABLE ' || tab_name || ' ADD (' ||
sensor || fehler_format || ' DEFAULT 1)',DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms);
ELSE
n_exception_flag := 1400;
raise_application_error(-20102, 'Fehler: Die Tabelle '||tab_name||' und/oder
Spalte '||sensor||' ist ungültig.');
END IF;
END IF;
n_exception_flag := 2000;
COMMIT;
DBMS_SQL.CLOSE_CURSOR(c_dbms);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler: Exception OTHERS in prozedur_DB_Spalte_anlegen.sql .');
DBMS_OUTPUT.PUT_LINE('-Flag: '||n_exception_flag||'.');
IF DBMS_SQL.IS_OPEN(c_dbms) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms);
END IF;
END;
/
COMMIT;
110
Anhang
Skript 21: PROZEDUR_DBMS_EXEC.SQL
----------------------------------------------------------------------------------------- Datei: PROZEDUR_DBMS_EXEC.SQL
-- Erstellt: 05.10.2000
-- Beschreibung:
-- Prodzedur führt eine DBMS_SQL Anweisung aus. Der STRING wird geparst und
-- ausgeführt.
--Änderungen:
------------------------------------------------------------------------------------------CREATE OR REPLACE PROCEDURE dbms_exec(STRING IN varchar2) AS
cursor_name
INTEGER;
dummy
INTEGER;
BEGIN
cursor_name := DBMS_SQL.OPEN_CURSOR;
--DDL statements are executed by the parse call, which
--performs the implied commit
DBMS_SQL.PARSE(cursor_name, string, DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(cursor_name);
COMMIT;
DBMS_SQL.CLOSE_CURSOR(cursor_name);
END;
/
COMMIT;
Skript 22: FROMS_COMMIT_ONLY.SQL
----------------------------------------------------------------------------------------- Datei: FROMS_COMMIT_ONLY.SQL
-- Erstellt: 01.12.2000
-- Beschreibung:
-- Forms behandelt ein COMMIT wie den Befehl COMMIT_FORM. Das kann, wenn man eine
Tabelle
-- z.B. in einem Trigger ändern will, zu Fehlern bzw. Fehleranzeigen führen.
-- Das COMMIT in einer Prozedur wird innerhalb der Datenbank wie ein COMMIT der
Datenbank
-- behandelt, aber Forms führt kein COMMIT_FORMS durch.
--Änderungen:
------------------------------------------------------------------------------------------CREATE OR REPLACE PROCEDURE forms_commit_only AS
BEGIN
COMMIT;
END;
/
COMMIT;
111
Anhang
Skript 23: PROZEDUR_FORMS_FUELL_FEHL_AUTO_ANZEIGE.SQL
--------------------------------------------------------------------------------------------------
Datei: PROZEDUR_FORMS_FUELL_FEHL_AUTO_ANZEIGE.SQL
Erstellt: 08.12.2000
Beschreibung:
Diese Funktion wird von dem Skript d:\zub_db\sql\forms\fehl_auto_anzeige.sql genutzt.
Füllt die Tabelle FEHL_AUTO_ANZEIGE_TAB für FORMS50 mit Werten aus ..._FEHL_ATUO_TAB,
die noch nicht als Checked gekennzeichnet wurden. Die Werte werden mit Anfangs- und
Endatum zusammengefasst. Bei FEHLER 1 (Datum nicht vorhanden) wird der Fehler auf
"ALLE" Sensoren und "ALLE" Raumnummern ausgeweitet, da bei einem fehlenden Datum in
ZUB_DATEN_TMP_TAB auch alle Daten fehlen. Der Fehler wird für jede Spaltenwert
einzeln pro Tabelle gezählt. D.h. z.B. enthält die Tabelle 4 Spalten wird bei
einem fehlenden Datum die Anzahl der Fehler auf 4 gesetzt.
-- Änderungen:
-----------------------------------------------------------------------------------------CREATE OR REPLACE PROCEDURE fuell_fehl_auto_anzeige(tab_name_ IN VARCHAR2, sensor_ IN
VARCHAR2, r_nr_ IN VARCHAR2, fehler_nr_ IN INTEGER) AS
-- Eingabe des Fehlerintervalls in Tagen. Erst wenn der Fehler die Dauer des Intervalls
-- nicht mehr auftritt, wird er erneut als Fehlerhaft markiert.
fehlerintervall
NUMBER(8,4) := 1/24;
n_exception_flag
NUMBER(6);
zaehler
NUMBER(8);
dat
DATE;
anfang_dat
DATE;
ende_dat
DATE;
ausgabe
VARCHAR2(255);
anzahl
NUMBER;
tmp_sensor
fehl_auto_anzeige_tab.sensor%TYPE;
tmp_r_nr
fehl_auto_anzeige_tab.r_nr%TYPE;
dummy INTEGER;
c_dbms INTEGER;
CURSOR c_vorh IS
SELECT anz_fehler FROM fehl_auto_anzeige_tab
WHERE UPPER(tab_name) = UPPER(tab_name_)
AND UPPER(sensor) = tmp_sensor
AND UPPER(r_nr) =tmp_r_nr
AND anf_dat = anfang_dat
AND end_dat = ende_dat
AND fehler_nr = fehler_nr_;
BEGIN
c_dbms := DBMS_SQL.OPEN_CURSOR;
n_exception_flag := 0;
tmp_sensor := UPPER(sensor_);
tmp_r_nr
:= UPPER(r_nr_);
-- FEHLER fehl_nr eintragen.
zaehler := 0;
ausgabe := 'SELECT datum FROM '||tab_name_||'_FEHL_AUTO_TAB WHERE '||sensor_||' =
'||fehler_nr_||' AND upper(r_nr) ='||CHR(39)||upper(r_nr_)||CHR(39)||' AND check_flag IS
NULL ORDER BY datum';
--DBMS_OUTPUT.PUT_LINE(ausgabe);
DBMS_SQL.PARSE(c_dbms,ausgabe,DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN(c_dbms,1,dat);
dummy := DBMS_SQL.EXECUTE(c_dbms);
n_exception_flag := 100;
<<fehler1>>
LOOP
IF DBMS_SQL.FETCH_ROWS(c_dbms) > 0 THEN
n_exception_flag := 1000;
DBMS_SQL.COLUMN_VALUE(c_dbms,1,dat);
IF zaehler = 0 THEN
-- Nur bei der ersten Schleife
ende_dat := dat;
anfang_dat := dat;
END IF;
112
Anhang
IF
dat > ende_dat + fehlerintervall THEN
-- Wenn der Fehler nicht mehr als 1 Std. auftritt
-- Werte eintragen.
--DBMS_OUTPUT.PUT_LINE('Schleife :'||zaehler||' Fehler
'||fehler_nr_||' Tabelle: '||tab_name_||' Sensor: '||sensor_||' Raum '||r_nr_ );
--DBMS_OUTPUT.PUT_LINE('
dat
'||to_char(dat,'dd.mm.yyyy hh24:mi')||' anfang '||to_char(anfang_dat,'dd.mm.yyyy
hh24:mi')||' ende '||to_char(ende_dat,'dd.mm.yyyy hh24:mi'));
IF fehler_nr_ = 1 THEN
tmp_sensor := 'ALLE';
tmp_r_nr
:= 'ALLE';
END IF;
OPEN c_vorh;
FETCH c_vorh INTO anzahl;
IF c_vorh%NOTFOUND THEN
INSERT INTO FEHL_AUTO_ANZEIGE_TAB( tab_name
, sensor
, r_nr , anz_fehler , anf_dat
, end_dat , fehler_nr)
VALUES
(tab_name_
, tmp_sensor, tmp_r_nr, zaehler
, anfang_dat , ende_dat , fehler_nr_);
COMMIT;
ELSE
-- Nur Fehler 1 (Datum nicht vorhanden wird gefunden!)
zaehler := zaehler + anzahl;
UPDATE FEHL_AUTO_ANZEIGE_TAB SET anz_fehler = zaehler
WHERE tab_name = tab_name_
AND sensor = tmp_sensor
AND r_nr = tmp_r_nr
AND anf_dat = anfang_dat
AND end_dat = ende_dat
AND fehler_nr = fehler_nr_;
END IF;
anfang_dat := dat;
-- Zähler zurücksetzten
zaehler := 0;
CLOSE c_vorh;
END IF;
ende_dat := dat;
zaehler := zaehler +1;
ELSE
n_exception_flag := 2000;
-- Keine Eintträge mehr gefunden.
-- Wurde irgenwann gezählt?
IF zaehler > 1 THEN
IF fehler_nr_ = 1 THEN
tmp_sensor := 'ALLE';
tmp_r_nr
:= 'ALLE';
END IF;
OPEN c_vorh;
FETCH c_vorh INTO anzahl;
--DBMS_OUTPUT.PUT_LINE('Ende :'||zaehler||' Fehler
'||fehler_nr_||' Tabelle: '||tab_name_||' Sensor: '||sensor_||' Raum '||r_nr_ );
--DBMS_OUTPUT.PUT_LINE('
dat '||to_char(dat,'dd.mm.yyyy
hh24:mi')||' anfang '||to_char(anfang_dat,'dd.mm.yyyy hh24:mi')||' ende
'||to_char(ende_dat,'dd.mm.yyyy hh24:mi'));
IF c_vorh%NOTFOUND THEN
INSERT INTO FEHL_AUTO_ANZEIGE_TAB( tab_name
, sensor
, r_nr , anz_fehler , anf_dat
, end_dat , fehler_nr)
VALUES
(tab_name_
, tmp_sensor, tmp_r_nr, zaehler
, anfang_dat , ende_dat , fehler_nr_);
COMMIT;
ELSE
-- Nur Fehler 1 (Datum nicht vorhanden wird gefunden!)
zaehler := zaehler + anzahl;
UPDATE FEHL_AUTO_ANZEIGE_TAB SET anz_fehler = zaehler
WHERE tab_name = tab_name_
AND sensor = tmp_sensor
AND r_nr = tmp_r_nr
AND anf_dat = anfang_dat
AND end_dat = ende_dat
AND fehler_nr = fehler_nr_;
END IF;
END IF;
EXIT fehler1;
END IF;
113
Anhang
END LOOP fehler1;
DBMS_SQL.CLOSE_CURSOR(c_dbms);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler: Exception OTHERS in Prozedur
FUELL_FEHL_AUTO_ANZEIGE.sql .');
DBMS_OUTPUT.PUT_LINE('-Flag: '||n_exception_flag||'.');
IF DBMS_SQL.IS_OPEN(c_dbms) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms);
END IF;
RAISE;
END;
/
COMMIT;
114
Anhang
Skript 24: PROZEDUR_FORMS_MESSBEREICH_FEHL_UPDATE.SQL
------------------------------------------------------------------------------------------------
Datei: PROZEDUR_FORMS_MESSBEREICH_FEHL_UPDATE.SQL
Erstellt: 10.12.2000
Beschreibung:
Diese Datei ist FORMS zugeordnet. Sie updatet die geänderten Messbereiche.
Bei einer Änderung des Messbereiches werden u. U. das "check_flag" und der
"Bearbeiter" gelöscht. Wenn mehrere Fehler in dieser aktualisierten Zeile vorhanden
sind, müssen diese Fehler wieder neu geprüft werden, obwohl Sie schon in der
Bearbeitungstabelle FEHL_INV stehen.
-------
Bem.:
Diese Funktion war ursprünglich in Forms selber geschrieben. Dabei wurde die
Bibliothek EXEC_SQL verwendet. Sie enthält allerdings einen BUG. Bei einer
Selektion des Datums und anschliessendem Parsen wird das Datum lediglich im
hh:mi - also 12 Std. Format - ausgegeben und nicht im hh24:mi Format. Das hat
zu einem Fehler beim Updaten geführt.
-- Änderungen:
-----------------------------------------------------------------------------------------CREATE OR REPLACE PROCEDURE forms_messbereich_fehl_update(HW_Adresse IN VARCHAR2) IS
--CREATE OR REPLACE PROCEDURE forms_messbereich_fehl_update(HW_Adresse IN VARCHAR2, num
IN INTEGER) IS
lfd_nr NUMBER(6);
i
NUMBER(4) := 0;
z
zuordnung%ROWTYPE;
c_1 INTEGER;
c_2 INTEGER;
dummy INTEGER;
ausgabe VARCHAR2(255);
d_datum DATE;
ch_datum VARCHAR2(50);
n_exception_flag NUMBER(4);
BEGIN
-- Initialisierung
SELECT nvl(max(nr),0) INTO lfd_nr FROM MESSBEREICH_GEAENDERT_TAB;
n_exception_flag := 0;
i := 0;
c_1 := DBMS_SQL.OPEN_CURSOR;
c_2 := DBMS_SQL.OPEN_CURSOR;
SELECT * INTO z FROM zuordnung WHERE HW_ADR = HW_Adresse;
-- Löschen der bisherigen Messbereichsabweichungen.
ausgabe := 'UPDATE '||z.tab_name||'_FEHL_AUTO_TAB SET '||z.sensor||' = NULL,
check_flag=NULL, Bearbeiter = NULL WHERE '||z.sensor||' = 3 AND upper(r_nr) =
'||CHR(39)||upper(z.r_nr)||CHR(39);
INSERT INTO MESSBEREICH_GEAENDERT_TAB VALUES(lfd_nr+3, ausgabe);
COMMIT;
DBMS_SQL.PARSE(c_1,ausgabe,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_1);
COMMIT;
-- Abfragen der neuen Messbereichsfehler
n_exception_flag := 200;
ausgabe := 'SELECT datum FROM '|| z.tab_name ||'_ROH_TAB WHERE '|| z.sensor ||' NOT
BETWEEN '||z.minwert||' AND '||z.maxwert||' AND '||z.sensor||' IS NOT NULL AND
upper(r_nr) ='||CHR(39)||upper(z.r_nr)||CHR(39);
INSERT INTO MESSBEREICH_GEAENDERT_TAB VALUES(lfd_nr+2, ausgabe);
COMMIT;
DBMS_SQL.PARSE(c_1,ausgabe,DBMS_SQL.NATIVE);
DBMS_SQL.DEFINE_COLUMN(c_1, 1, d_datum);
dummy := DBMS_SQL.EXECUTE(c_1);
n_exception_flag := 300;
<<mess_update>>
LOOP
115
Anhang
IF DBMS_SQL.FETCH_ROWS(c_1) > 0 THEN
i := i + 1;
n_exception_flag := 500;
-- Datums heraussuchen.
DBMS_SQL.COLUMN_VALUE(c_1, 1, d_datum);
ch_datum := to_char(d_datum,'dd.mm.yyyy hh24:mi');
IF datum_r_nr_in_tab(d_datum, z.r_nr, z.tab_name||'_FEHL_AUTO_TAB')= TRUE
THEN
-- Datum, Raumnummer vorhanden -> UPDATE
ausgabe := 'UPDATE '||z.tab_name||'_FEHL_AUTO_TAB SET
'||z.sensor||' = 3, check_flag = NULL, Bearbeiter = NULL WHERE upper(r_nr) =
'||CHR(39)||upper(z.r_nr)||CHR(39)||' AND '||z.sensor||' IS NULL AND datum =
to_date('||CHR(39)||ch_datum||CHR(39)||','||CHR(39)||'dd.mm.yyyy hh24:mi'||CHR(39)||')';
ELSE
-- Datum, Raumnummer nicht vorhanden -> INSERT
ausgabe := 'INSERT INTO '||z.tab_name||'_FEHL_AUTO_TAB
(datum,r_nr,'||z.sensor||') VALUES
(to_date('||CHR(39)||ch_datum||CHR(39)||','||CHR(39)||'dd.mm.yyyy
hh24:mi'||CHR(39)||'),'||CHR(39)||upper(z.r_nr)||CHR(39)||', 3)';
END IF;
DBMS_SQL.PARSE(c_2,ausgabe,DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_2);
COMMIT;
ELSE
INSERT INTO MESSBEREICH_GEAENDERT_TAB VALUES(lfd_nr+4, ' Es wurden
'||i||' Fehler markiert.');
COMMIT;
INSERT INTO MESSBEREICH_GEAENDERT_TAB VALUES(lfd_nr+1, 'Letzter Befehl:
'||ausgabe);
COMMIT;
EXIT mess_update;
END IF;
n_exception_flag := 1000;
COMMIT;
END LOOP mess_update;
n_exception_flag := 2000;
DBMS_SQL.CLOSE_CURSOR(c_1);
DBMS_SQL.CLOSE_CURSOR(c_2);
EXCEPTION
WHEN NO_DATA_FOUND THEN
IF DBMS_SQL.IS_OPEN(c_1) THEN
DBMS_SQL.CLOSE_CURSOR(c_1);
END IF;
IF DBMS_SQL.IS_OPEN(c_2) THEN
DBMS_SQL.CLOSE_CURSOR(c_2);
END IF;
DBMS_OUTPUT.PUT_LINE('Keine Daten gefunden. Prozedur UPDATE_FEHLERTABS. Flag:
'||n_exception_flag);
RAISE;
WHEN OTHERS THEN
IF DBMS_SQL.IS_OPEN(c_1) THEN
DBMS_SQL.CLOSE_CURSOR(c_1);
END IF;
IF DBMS_SQL.IS_OPEN(c_2) THEN
DBMS_SQL.CLOSE_CURSOR(c_2);
END IF;
DBMS_OUTPUT.PUT_LINE('Unbehandelte Exception in Prozedur UPDATE_FEHLERTABS. Flag:
'||n_exception_flag);
RAISE;
END;
/
COMMIT;
116
Anhang
Skript 25: PROZEDUR_ZUB_DATEN_TMP_TAB_ANLEGEN.SQL
----------------------------------------------------------------------------------------- Datei: PROZEDUR_ZUB_DATEN_TMP_TAB_ANLEGEN.SQL
-- Erstellt: 13.11.2000
-- Beschreibung:
-- Automatisches Einfügen von Spalten in die Tabelle ZUB_DATEN_TMP_TAB
-- mit den Einträgen Hw_Adr aus der Tabelle ZUORDNUNG. Die Fehlerprüfung von ZUORDNUNG
-- muss korrekt sein.
---- Bem.:
-- Die Tabelle ZUB_DATEN_TMP_TAB wurde in Umgebungstabellen.sql angelegt mit den
-- Spalten datum und uhrzeit als VARCHAR2
--Änderungen:
------------------------------------------------------------------------------------------SET SERVEROUTPUT ON
CREATE OR REPLACE PROCEDURE zub_daten_tmp_tab_anlegen IS
binaer
VARCHAR2(20) := ' NUMBER(1)';
analog
VARCHAR2(20) := ' NUMBER(5,2)';
analog_binaer
zuordnung.format%TYPE;-- entspricht der Spalte FORMAT in
ZUORDNUNG
c_dbms
INTEGER;
dummy
INTEGER;
hw_adr_neu
Zuordnung.hw_adr%TYPE;
CURSOR c_hw_adr_neu
IS
SELECT upper(hw_adr) hw_adr FROM zuordnung z
MINUS
SELECT user_tab.column_name FROM user_tab_columns user_tab
WHERE user_tab.table_name = 'ZUB_DATEN_TMP_TAB';
CURSOR c_format
IS SELECT
WHERE hw_adr_neu = hw_adr;
upper(format) format FROM zuordnung z
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
DBMS_OUTPUT.PUT_LINE('--*****************************************************--');
DBMS_OUTPUT.PUT_LINE('-Prozedur: ZUB_DATEN_TMP_TAB_ANLEGEN');
DBMS_OUTPUT.PUT_LINE('-prozedur_zub_daten_tmp_tab_anlegen.sql');
c_dbms := DBMS_SQL.OPEN_CURSOR;
-- Anlegen der Tabellennamen, wie sie in der Tabelle Zuordnung stehen.
FOR c IN c_hw_adr_neu LOOP
-- Diese Spalten sind in ZUB_DATEN_TMP_TAB nicht vorhanden.
hw_adr_neu := c.hw_adr;
OPEN c_format;
FETCH c_format INTO analog_binaer; -- Selektieren aus ZUORDNUNG, ob es sich um
einen Binär- oder Analogwert handelt.
IF c_format%NOTFOUND THEN
analog_binaer := NULL;
END IF;
IF SUBSTR(UPPER(analog_binaer),1,2) = 'B' THEN
-- Binärwert
DBMS_SQL.PARSE(c_dbms,'ALTER TABLE ZUB_DATEN_TMP_TAB ADD (' || hw_adr_neu
|| binaer || ')',DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms);
DBMS_OUTPUT.PUT_LINE('-- Spalte '|| hw_adr_neu ||' im Format '|| binaer
||' in ZUB_DATEN_TMP_TAB eingefügt.');
ELSIF SUBSTR(UPPER(analog_binaer),1,2) = 'A' THEN
-- Analogwert
DBMS_SQL.PARSE(c_dbms,'ALTER TABLE ZUB_DATEN_TMP_TAB ADD (' || hw_adr_neu
|| analog || ')',DBMS_SQL.NATIVE);
dummy := DBMS_SQL.EXECUTE(c_dbms);
DBMS_OUTPUT.PUT_LINE('-- Spalte '|| hw_adr_neu ||' im Format '|| analog
||' in ZUB_DATEN_TMP_TAB eingefügt.');
ELSE
DBMS_OUTPUT.PUT_LINE('-- FEHLER: Die Spalte "Format" in ZUORDNUNG muss
ein A für Analogwert oder B für Binärwert enthalten.');
117
Anhang
DBMS_OUTPUT.PUT_LINE('-starten Sie das Skript erneut.');
DBMS_OUTPUT.PUT_LINE('-nicht geändert.');
END IF;
CLOSE c_format;
-- Eintrag in die Tabelle
COMMIT;
END LOOP;
DBMS_SQL.CLOSE_CURSOR(c_dbms);
Verbessern Sie den Fehler und
Die Tabelle ZUB_DATEN_TMP_TAB wird
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler: Exception OTHERS in
prozedur_zub_daten_tmp_tab_anlegen.sql.');
IF c_hw_adr_neu%ISOPEN THEN
CLOSE c_hw_adr_neu;
END IF;
IF c_format%ISOPEN THEN
CLOSE c_format;
END IF;
IF DBMS_SQL.IS_OPEN(c_dbms) THEN
DBMS_SQL.CLOSE_CURSOR(c_dbms);
END IF;
RAISE;
END;
/
COMMIT;
--select table_name from user_tables;
--desc Klima;
--desc StdR;
118
Anhang
Skript 26: SPOOL_FEHLER_TABS.SQL
----------------------------------------------------------------------------------------- Datei: SPOOL_FEHLER_TABS.SQL
-- Erstellt: 07.12.2000
-- Beschreibung:
-- Spoolt die Tabelle FEHL_AUTO_ANZ_TAB und die Tabelle FEHL_TAB
-- in unten genanntes TXT-File.
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON;
SET Space 0
SET LINESIZE 500
--SET termout off;
--SET echo off;
--SET heading off;
SET Space 4
SET Feedback off
SPOOL d:\zub_db\sql\meldungen\fehler_tabs.txt
DECLARE
anz NUMBER(6);
BEGIN
DBMS_OUTPUT.PUT_LINE('-- Datei erstellt am '||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('********** FEHL_AUTO_ANZEIGE_TAB **********');
SELECT count(*) INTO anz FROM fehl_auto_anzeige_tab;
IF anz = 0 THEN
DBMS_OUTPUT.PUT_LINE('FEHL_AUTO_ANZEIGE_TAB ist leer!');
DBMS_OUTPUT.PUT_LINE('.');
DBMS_OUTPUT.PUT_LINE('.');
DBMS_OUTPUT.PUT_LINE('------------------------------------------------------');
END IF;
END;
/
select
RPAD(TAB_NAME,10,' ') Tabelle,
RPAD(SENSOR,10,' ') Sensor,
R_NR,
RPAD(ANZ_FEHLER,5,' ') Anzeige_Fehler,
to_char(ANF_DAT,'dd.mm.yyyy hh24:mi'),
to_char(END_DAT,'dd.mm.yyyy hh24:mi'),
RPAD(FEHLER_NR,9,' ') Fehler_Nr,
CHECK_FLAG,
LPAD(BEARBEITER,10,' ') Bearbeiter
FROM fehl_auto_anzeige_tab
order by tab_name, fehler_nr, anf_dat, r_nr, sensor;
DECLARE
anz NUMBER(6);
BEGIN
DBMS_OUTPUT.PUT_LINE('.');
DBMS_OUTPUT.PUT_LINE('.');
DBMS_OUTPUT.PUT_LINE('******************************************************************
***********');
DBMS_OUTPUT.PUT_LINE('******************************************************************
***********');
DBMS_OUTPUT.PUT_LINE('********** FEHL_TAB **********');
SELECT count(*) INTO anz FROM fehl_tab;
IF anz = 0 THEN
DBMS_OUTPUT.PUT_LINE('FEHL_TAB ist leer!');
DBMS_OUTPUT.PUT_LINE('.');
DBMS_OUTPUT.PUT_LINE('.');
DBMS_OUTPUT.PUT_LINE('------------------------------------------------------');
END IF;
END;
/
119
Anhang
SELECT
Lfd_Nr,
RPAD(TAB_NAME,10,' ') Tabelle,
RPAD(SENSOR,10,' ') Sensor,
R_NR,
RPAD(FEHLER_NR,9,' ') Fehler_Nr,
to_char(ANF_DAT,'dd.mm.yyyy hh24:mi') Anfang,
to_char(END_DAT,'dd.mm.yyyy hh24:mi') Ende,
RPAD(BEARBEITER,10,' ') Bearbeiter,
Bemerkung
FROM fehl_tab
order by lfd_nr;
DECLARE
anz NUMBER(6);
BEGIN
DBMS_OUTPUT.PUT_LINE('.');
DBMS_OUTPUT.PUT_LINE('.');
DBMS_OUTPUT.PUT_LINE('******************************************************************
***********');
DBMS_OUTPUT.PUT_LINE('******************************************************************
***********');
DBMS_OUTPUT.PUT_LINE('********** MOEGLICHE_UEBERSCHNEIDUNG_TAB **********');
SELECT count(*) INTO anz FROM moegliche_ueberschneidung_tab;
IF anz = 0 THEN
DBMS_OUTPUT.PUT_LINE('MOEGLICHE_UEBERSCHNEIDUNG_TAB ist leer!');
DBMS_OUTPUT.PUT_LINE('.');
DBMS_OUTPUT.PUT_LINE('.');
DBMS_OUTPUT.PUT_LINE('------------------------------------------------------');
END IF;
END;
/
SELECT
RPAD(NR,4,' ') Nr,
RPAD(TAB_NAME,10,' ') Tabelle,
RPAD(SENSOR,10,' ') Sensor,
R_NR,
RPAD(ANZ_FEHLER,10,' ') Anz_Fehler,
to_char(ANF_DAT,'dd.mm.yyyy hh24:mi') Anfang,
to_char(END_DAT,'dd.mm.yyyy hh24:mi') Ende,
RPAD(FEHLER_NR,9,' ') Fehler_Nr,
CHECK_FLAG,
RPAD(BEARBEITER,10,' ') Bearbeiter
FROM moegliche_ueberschneidung_tab
order by nr ASC;
SPOOL OFF
EXIT;
120
Anhang
Skript 27: SPOOL_KOPIEREN_NACH_ZUB_DATEN_TMP_TAB.SQL
----------------------------------------------------------------------------------------- Datei: SPOOL_KOPIEREN_NACH_ZUB_DATEN_TMP_TAB.SQL
-- Erstellt: 06.11.2000
-- Beschreibung:
-- Wird nur zum Testen der Datenbank benötigt. Dieses Skript kopiert alle Werte aus
Daten
-- nach ZUB_DATEN_TMP_TAB.
--
--Änderungen:
--------------------------------------------------------------------------------------------SET SERVEROUTPUT ON;
--SET termout off;
--SET echo off;
--SET heading off;
--SET feedback off;
--SET LINESIZE 255
SPOOL d:\zub_db\sql\test\kopieren_nach_zub_daten_tmp_tab.sql
DECLARE
hk
CHAR(1);
tmp_tab_name
zuordnung.tab_name%TYPE;
tmp_r_nr
zuordnung.r_nr%TYPE := NULL;
letzterSensor
zuordnung.sensor%TYPE := NULL;
strout
VARCHAR(50) := NULL;
flag
NUMBER(1) := 0;
--spalte
user_tab_columns.column_name%TYPE;
letzte_spalte user_tab_columns.column_name%TYPE;
r_nr_alt
zuordnung.r_nr%TYPE := NULL;
-- Nur Tabellennamen auslesen
-- Tabellennamen und Raumnummern auslesen.
CURSOR c_spalte IS SELECT UPPER(column_name) spaltenname FROM user_tab_columns WHERE
table_name = 'ZUB_DATEN_TMP_TAB'
AND UPPER(column_name) NOT IN ('DATUM', 'UHRZEIT')
ORDER BY column_name ASC;
-- Spaltennamen auslesen.
--CURSOR c_spalte IS
--SELECT user_tab.column_name spalte FROM user_tab_columns user_tab
--WHERE upper(tmp_tab_name) = upper(user_tab.table_name)
--ORDER BY user_tab.column_name ASC;
c_dbms INTEGER;
dummy
INTEGER;
------------------------------------------------------------------------------------------BEGIN
DBMS_OUTPUT.ENABLE(1000000);
SELECT strich INTO hk FROM hochkomma;
DBMS_OUTPUT.PUT_LINE('---------------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- DIES IST EIN TESTSKRIPT!!!!!!!!!!!!!!!!');
DBMS_OUTPUT.PUT_LINE('-- Datei: KOPIEREN_NACH_ZUB_DATEN_TMP_TAB.SQL');
DBMS_OUTPUT.PUT_LINE('-- Erstellt: '||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('-- Aus Datei KOPIEREN_NACH_ZUB_DATEN_TMP_TAB');
DBMS_OUTPUT.PUT_LINE('-- Beschreibung: ');
DBMS_OUTPUT.PUT_LINE('-- Kopieren der Daten aus DATEN nach ZUB_DATEN_TMP_TAB.');
DBMS_OUTPUT.PUT_LINE('---------------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-- Leeren der temprären Tabellen');
DBMS_OUTPUT.PUT_LINE('TRUNCATE TABLE ZUB_DATEN_TMP_TAB;');
121
Anhang
DBMS_OUTPUT.PUT_LINE('COMMIT;');
DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-- Kopieren der Werte in die temporären Tabellen, ');
DBMS_OUTPUT.PUT_LINE('-- bei denen das Datum neuer ist als in den Rohdatentabellen.');
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
DBMS_OUTPUT.PUT_LINE('INSERT INTO ZUB_DATEN_TMP_TAB (datum, uhrzeit, ');
SELECT MAX(UPPER(column_name)) INTO letzterSensor FROM user_tab_columns
WHERE upper(table_name)='ZUB_DATEN_TMP_TAB'
AND UPPER(column_name) NOT IN ('DATUM', 'UHRZEIT')
ORDER BY column_name ;
FOR n IN c_spalte LOOP
IF UPPER(n.spaltenname) = UPPER(letzterSensor) THEN
strout := n.spaltenname || ')';
ELSE
strout := n.spaltenname || ', ';
END IF;
DBMS_OUTPUT.PUT_LINE(strout);
END LOOP;
DBMS_OUTPUT.PUT_LINE('SELECT datum, uhrzeit, ');
FOR z IN c_spalte LOOP
IF UPPER(z.spaltenname) = UPPER(letzterSensor) THEN
strout := z.spaltenname;
ELSE
strout := z.spaltenname || ', ';
END IF;
DBMS_OUTPUT.PUT_LINE(strout);
END LOOP;
DBMS_OUTPUT.PUT_LINE('FROM DATEN;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
--DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
--DBMS_OUTPUT.PUT_LINE('-- Löschen ungültiger Einträge von ZUB_DATEN_TMP_TAB');
--DBMS_OUTPUT.PUT_LINE('DELETE FROM ZUB_DATEN_TMP_TAB WHERE datum IS NULL OR uhrzeit IS
NULL;');
--DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler: Exception OTHERS in
SPOOL_KOPIEREN_NACH_ZUB_DATEN_TMP_TAB.SQL.');
IF c_spalte%ISOPEN THEN
CLOSE c_spalte;
END IF;
END;
/
COMMIT;
SPOOL OFF;
--EXIT;
122
Anhang
Skript 28: SPOOL_ROHDATEN_EINTRAGEN.SQL
----------------------------------------------------------------------------------------- Datei: SPOOL_Rohdaten_eintragen.SQL
-- Erstellt: 06.11.2000
-- Beschreibung:
-- Spoolt die Datei Rohdaten_eintragen.sql zum Kopieren der Tabelle ZUB_DATEN_TMP_TAB
-- in die einzelnen ...TMP_TAB Tabellen der Datenbank.
--
--Änderungen:
------------------------------------------------------------------------------------------SET SERVEROUTPUT ON;
SET termout off;
SET echo off;
SET heading off;
SET feedback off;
SET LINESIZE 200
SPOOL d:\zub_db\sql\Rohdaten_eintragen.sql
DECLARE
hk
tmp_tab_name
tmp_R_Nr
letzterSensor
ausgabe
R_Nr_alt
CHAR(1);
zuordnung.tab_name%TYPE;
zuordnung.R_Nr%TYPE := NULL;
zuordnung.sensor%TYPE := NULL;
VARCHAR2(250) := NULL;
zuordnung.R_Nr%TYPE := NULL;
-- Nur Tabellennamen auslesen
CURSOR c_tab_name IS SELECT DISTINCT upper(tab_name) tab_name from zuordnung
ORDER BY tab_name;
-- Tabellennamen und Raumnummern auslesen.
CURSOR c_namen IS SELECT DISTINCT upper(tab_name) tab_name, upper(R_Nr) R_Nr from
zuordnung
ORDER BY tab_name, R_Nr;
-- Restliche Zeile aus Zuordnung selektieren.
CURSOR c_zeile IS SELECT upper(hw_adr) hw_adr, upper(R_Nr) R_Nr, upper(sensor) sensor
FROM zuordnung
WHERE upper(tmp_tab_name) = upper(tab_name)
AND upper(R_Nr) = upper(tmp_R_Nr)
ORDER BY hw_adr ASC;
-----------------------------------------------------------------------------------------BEGIN
DBMS_OUTPUT.ENABLE(1000000);
SELECT strich INTO hk FROM hochkomma;
DBMS_OUTPUT.PUT_LINE('-- Datei erstellt am '||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('---------------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Datei: Rohdaten_eintragen.sql');
DBMS_OUTPUT.PUT_LINE('-- Erstellt: '||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('-- Aus Datei SPOOL_Rohdaten_eintragen');
DBMS_OUTPUT.PUT_LINE('-- Beschreibung: ');
DBMS_OUTPUT.PUT_LINE('-- Kopieren der Daten aus ZUB_DATEN_TMP_TAB in die Datenbank TMP
Tabellen ');
DBMS_OUTPUT.PUT_LINE('---------------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-- Leeren der temporären Tabellen');
FOR n IN c_tab_name LOOP
DBMS_OUTPUT.PUT_LINE('TRUNCATE TABLE '||n.tab_name||'_TMP_TAB;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
END LOOP;
123
Anhang
DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-- Löschen ungültiger Einträge von ZUB_DATEN_TMP_TAB');
DBMS_OUTPUT.PUT_LINE('DELETE FROM ZUB_DATEN_TMP_TAB WHERE Datum IS NULL OR Uhrzeit IS
NULL;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-- Kopieren der Werte in die temporären Tabellen, ');
DBMS_OUTPUT.PUT_LINE('-- bei denen das Datum neuer ist als in den Rohdatentabellen.');
FOR n IN c_namen LOOP
ausgabe := NULL;
tmp_tab_name := n.tab_name; -- Tabellennamen und
tmp_R_Nr := n.R_Nr;
-- Raumnummer aus Zuordnung selektieren.
R_Nr_alt := n.R_Nr;
-- erste Raumnummer!
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
DBMS_OUTPUT.PUT_LINE('INSERT INTO '|| tmp_tab_name ||'_TMP_TAB (Datum, R_Nr, ');
FOR z IN c_zeile LOOP -- Restliche Zeilen aus ZUORDNUNG in der 'tmp_tab_name'
steht.
IF spalte_in_tabelle('ZUB_DATEN_TMP_TAB',z.hw_adr) = TRUE THEN
SELECT MAX(hw_adr) INTO letzterSensor FROM zuordnung WHERE
upper(tmp_tab_name) = upper(tab_name) AND upper(R_Nr) = upper(tmp_R_Nr) ORDER BY hw_adr;
IF z.R_Nr = R_Nr_alt THEN
IF UPPER(z.hw_adr) = UPPER(letzterSensor) THEN
ausgabe := ausgabe || z.sensor || ')';
DBMS_OUTPUT.PUT_LINE(ausgabe);
ELSE
ausgabe := ausgabe || z.sensor || ', ';
IF LENGTH(ausgabe) > 150 THEN
DBMS_OUTPUT.PUT_LINE(ausgabe);
ausgabe := NULL;
END IF;
END IF;
R_Nr_alt := z.R_Nr;
END IF;
END IF;
END LOOP;
ausgabe := NULL;
DBMS_OUTPUT.PUT_LINE('SELECT to_date(Datum||Uhrzeit,'||hk||'dd.mm.yyyy
hh24:mi'||hk||'), '||hk||tmp_R_Nr||hk||', ');
FOR z IN c_zeile LOOP -- Restliche Zeilen aus ZUORDNUNG in der 'tmp_tab_name'
steht.
IF spalte_in_tabelle('ZUB_DATEN_TMP_TAB',z.hw_adr) = TRUE THEN
-SELECT MAX(sensor) INTO letzterSensor FROM zuordnung WHERE
upper(tmp_tab_name) = upper(tab_name) AND upper(R_Nr) = upper(tmp_R_Nr);
IF z.R_Nr = R_Nr_alt THEN
IF UPPER(z.hw_adr) = UPPER(letzterSensor) THEN
ausgabe := ausgabe||z.hw_adr;
DBMS_OUTPUT.PUT_LINE(ausgabe);
ELSE
ausgabe := ausgabe|| z.hw_adr || ', ';
IF LENGTH(ausgabe) > 150 THEN
DBMS_OUTPUT.PUT_LINE(ausgabe);
ausgabe := NULL;
END IF;
END IF;
R_Nr_alt := z.R_Nr;
END IF;
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('FROM ZUB_DATEN_TMP_TAB');
DBMS_OUTPUT.PUT_LINE('WHERE to_date(Datum||Uhrzeit,'||hk||'dd.mm.yyyy
hh24:mi'||hk||') > (SELECT
nvl(max(Datum),to_date('||hk||'01.01.1111'||hk||','||hk||'dd.mm.yyyy hh24:mi'||hk||'))')
;
DBMS_OUTPUT.PUT_LINE('
FROM
'||tmp_tab_name||'_ROH_TAB') ;
DBMS_OUTPUT.PUT_LINE('
WHERE
R_Nr ='||hk|| tmp_R_Nr||hk||');') ;
DBMS_OUTPUT.PUT_LINE('COMMIT;');
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
END LOOP;
124
Anhang
DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-- Kopieren der Temporären Daten in die Rohdatentabellen');
FOR n IN c_tab_name LOOP
DBMS_OUTPUT.PUT_LINE('INSERT INTO '||n.tab_name||'_ROH_TAB SELECT * FROM
'||n.tab_name||'_TMP_TAB;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
END LOOP;
DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler: Exception OTHERS in spool_Rohdaten_eintragen.sql.');
IF c_zeile%ISOPEN THEN
CLOSE c_zeile;
END IF;
IF c_namen%ISOPEN THEN
CLOSE c_namen;
END IF;
IF c_tab_name%ISOPEN THEN
CLOSE c_tab_name;
END IF;
END;
/
COMMIT;
SET FEEDBACK ON;
SPOOL OFF;
125
Anhang
Skript 29: SPOOL_ROHKORR.SQL
-----------------------------------------------------------------------------------------------
Datei: SPOOL_ROHKORR.SQL
Erstellt: 21.11.2000
Beschreibung:
Aus den Tabellen ..._FEHL_INV_TAB und den Tabellen ..._ROH_TAB
werden die Tabellen ..._ROHKORR_TAB gefüllt.
Dieses Skript spoolt die reine SQL Datei ROHKORR.sql, die obige
Angaben ausführt.
-- Bem.:
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON;
SET termout off;
SET echo off;
SET heading off;
SET feedback off;
SET LINESIZE 200
SPOOL d:\zub_db\sql\ROHKORR.sql
DECLARE
-- Minimale Anzahl der Werte in ..._ROHKORR_TAB pro Tag, damit ein Mittelwert übernommen
wird.
min_anz_rohkorrwerte_pro_tag NUMBER(5) := 230;
hk
CHAR(1);
tmp_tab_name
zuordnung.tab_name%TYPE;
letzterSensor
zuordnung.sensor%TYPE := NULL;
ausgabe
VARCHAR2(255) := NULL;
-- Nur Tabellennamen auslesen
CURSOR c_tab_name IS SELECT DISTINCT upper(tab_name) tab_name from zuordnung
ORDER BY tab_name;
-- Sensoren aus Zuordnung selektieren.
CURSOR c_sensor IS SELECT DISTINCT upper(sensor) sensor FROM zuordnung
WHERE upper(tmp_tab_name) = upper(tab_name)
ORDER BY sensor ASC;
------------------------------------------------------------------------------------------BEGIN
DBMS_OUTPUT.ENABLE(1000000);
SELECT strich INTO hk FROM hochkomma; -- das Zeichen ' in hk speichern.
DBMS_OUTPUT.PUT_LINE('-- Datei erstellt am '||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Datei: ROHKORR.SQL');
DBMS_OUTPUT.PUT_LINE('-- Erstellt: '||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('-- Aus Datei SPOOL_ROHKORR.SQL');
DBMS_OUTPUT.PUT_LINE('-- Beschreibung: ');
DBMS_OUTPUT.PUT_LINE('-- Füllen der Tabellen ..._ROHKORR_TAB:');
DBMS_OUTPUT.PUT_LINE('-- ..._ROHKORR_TAB wird durch Multiplikation der Tabellen
..._ROH_TAB und ');
DBMS_OUTPUT.PUT_LINE('-- ..._FEHL_INV_TAB gefüllt. ');
DBMS_OUTPUT.PUT_LINE('-------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-- Leeren der Tabellen ..._ROHKORR_TAB');
FOR n IN c_tab_name LOOP
DBMS_OUTPUT.PUT_LINE('TRUNCATE TABLE '||n.tab_name||'_ROHKORR_TAB;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
END LOOP;
---------------------------------------------------------------------------------------DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
126
Anhang
DBMS_OUTPUT.PUT_LINE('-- Füllen der Tabellen ..._ROHKORR_TAB');
FOR n IN c_tab_name LOOP
ausgabe := NULL;
tmp_tab_name := n.tab_name;
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
DBMS_OUTPUT.PUT_LINE('INSERT INTO '|| tmp_tab_name ||'_ROHKORR_TAB (Datum, R_Nr,
');
FOR z IN c_sensor LOOP -- Restliche Zeilen aus ZUORDNUNG in der 'tmp_tab_name'
steht.
IF spalte_in_tabelle(tmp_tab_name||'_ROHKORR_TAB',z.sensor) = TRUE THEN
SELECT MAX(sensor) INTO letzterSensor FROM zuordnung
WHERE upper(tmp_tab_name) = upper(tab_name) ORDER BY sensor;
IF UPPER(z.sensor) = UPPER(letzterSensor) THEN
ausgabe := ausgabe|| z.sensor || ')';
DBMS_OUTPUT.PUT_LINE(ausgabe);
ELSE
ausgabe := ausgabe|| z.sensor || ', ';
IF LENGTH(ausgabe) > 150 THEN
DBMS_OUTPUT.PUT_LINE(ausgabe);
ausgabe := NULL;
END IF;
END IF;
END IF;
END LOOP;
ausgabe := NULL;
DBMS_OUTPUT.PUT_LINE('SELECT r.Datum ,r.R_Nr , ');
FOR z IN c_sensor LOOP -- Restliche Zeilen aus ZUORDNUNG in der 'tmp_tab_name'
steht.
IF spalte_in_tabelle(tmp_tab_name||'_ROHKORR_TAB',z.sensor) = TRUE THEN
IF UPPER(z.sensor) = UPPER(letzterSensor) THEN
ausgabe := ausgabe||'f.'||z.sensor||' * r.'||z.sensor;
DBMS_OUTPUT.PUT_LINE(ausgabe);
ELSE
ausgabe :=ausgabe|| 'f.'||z.sensor||' * r.'||z.sensor||',
';
IF LENGTH(ausgabe) > 150 THEN
DBMS_OUTPUT.PUT_LINE(ausgabe);
ausgabe := NULL;
END IF;
END IF;
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('FROM '||tmp_tab_name||'_ROH_TAB r,
'||tmp_tab_name||'_FEHL_INV_TAB f');
DBMS_OUTPUT.PUT_LINE('WHERE r.Datum = f.Datum');
DBMS_OUTPUT.PUT_LINE('AND r.R_Nr = f.R_Nr;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
END LOOP;
END;
/
SET FEEDBACK ON;
SPOOL OFF;
127
Anhang
Skript 30: SPOOL_TAGMONATJAHR.SQL
----------------------------------------------------------------------------------------- Datei: SPOOL_TAGMONATJAHR.SQL
-- Erstellt: 21.11.2000
-- Beschreibung:
-- Aus der Tabelle ..._ROHKORR_TAB werden die Tabellen ..._TAG_TAB, ..._MONAT_TAB,
-- und JAHR_TAB gefüllt.
-- Diese Datei spoolt das reine SQL Skript TagMonatJahr.sql, welches zum Füllen
-- der Datentabellen benötigt wird.
-----
**************************************
Der Anwender kann unten eintragen, wieviele Messwerte pro Tag, Monat, Jahr vorhanden
sein müssen, damit die Werte übernommen werden.
**************************************
-- Bem.:
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON;
SET termout off;
SET echo off;
SET heading off;
SET feedback off;
SET LINESIZE 80
SPOOL d:\zub_db\sql\TagMonatJahr.sql
DECLARE
-- Minimale Anzahl der Werte in ..._ROHKORR_TAB pro Tag, damit ein Mittelwert übernommen
wird.
min_anz_rohkorrwerte_pro_tag NUMBER(5) := 230;
hk
CHAR(1);
tmp_tab_name
zuordnung.tab_name%TYPE;
letzterSensor
zuordnung.sensor%TYPE := NULL;
ausgabe
VARCHAR2(50) := NULL;
-- Nur Tabellennamen auslesen
CURSOR c_tab_name IS SELECT DISTINCT upper(tab_name) tab_name from zuordnung
ORDER BY tab_name;
-- Sensoren aus Zuordnung selektieren.
CURSOR c_sensor IS SELECT DISTINCT upper(sensor) sensor FROM zuordnung
WHERE upper(tmp_tab_name) = upper(tab_name)
ORDER BY sensor ASC;
------------------------------------------------------------------------------------------BEGIN
DBMS_OUTPUT.ENABLE(1000000);
SELECT strich INTO hk FROM hochkomma; -- das Zeichen ' in hk speichern.
DBMS_OUTPUT.PUT_LINE('-- Datei erstellt am '||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('---------------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- Datei: TAGMONATJAHR.SQL');
DBMS_OUTPUT.PUT_LINE('-- Erstellt: '||to_char(SYSDATE,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('-- Aus Datei SPOOL_TAGMONATJAHR.SQL');
DBMS_OUTPUT.PUT_LINE('-- Beschreibung: ');
DBMS_OUTPUT.PUT_LINE('-- Füllen der Tabellen ..._TAG_TAB, ..._MONAT_TAB, ..._JAHR_TAB
');
DBMS_OUTPUT.PUT_LINE('---------------------------------------------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-- Leeren der Tabellen ..._TAG_TAB, ..._MONAT_TAB, ..._JAHR_TAB');
FOR n IN c_tab_name LOOP
DBMS_OUTPUT.PUT_LINE('TRUNCATE TABLE '||n.tab_name||'_TAG_TAB;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
END LOOP;
128
Anhang
FOR n IN c_tab_name LOOP
DBMS_OUTPUT.PUT_LINE('TRUNCATE TABLE '||n.tab_name||'_MONAT_TAB;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
END LOOP;
FOR n IN c_tab_name LOOP
DBMS_OUTPUT.PUT_LINE('TRUNCATE TABLE '||n.tab_name||'_JAHR_TAB;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
END LOOP;
DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-Füllen der Tabellen ..._TAG_TAB');
DBMS_OUTPUT.PUT_LINE('-Es müssen mindestens '||min_anz_rohkorrwerte_pro_tag||' von
240 Tagesdaten vorhanden sein.');
FOR n IN c_tab_name LOOP
tmp_tab_name := n.tab_name;
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
DBMS_OUTPUT.PUT_LINE('INSERT INTO '|| tmp_tab_name ||'_TAG_TAB (datum, r_nr, ');
FOR z IN c_sensor LOOP -- Restliche Zeilen aus ZUORDNUNG in der 'tmp_tab_name'
steht.
IF spalte_in_tabelle(tmp_tab_name||'_TAG_TAB',z.sensor) = TRUE THEN
SELECT MAX(sensor) INTO letzterSensor FROM zuordnung
WHERE upper(tmp_tab_name) = upper(tab_name) ORDER BY sensor;
IF UPPER(z.sensor) = UPPER(letzterSensor) THEN
ausgabe := z.sensor || ')';
ELSE
ausgabe := z.sensor || ', ';
END IF;
DBMS_OUTPUT.PUT_LINE(ausgabe);
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('SELECT TRUNC(r.datum,'||hk||'DD'||hk||') ,r.r_nr , ');
FOR z IN c_sensor LOOP -- Restliche Zeilen aus ZUORDNUNG in der 'tmp_tab_name'
steht.
IF spalte_in_tabelle(tmp_tab_name||'_TAG_TAB',z.sensor) = TRUE THEN
IF UPPER(z.sensor) = UPPER(letzterSensor) THEN
ausgabe := 'avg(r.'||z.sensor||')';
ELSE
ausgabe := 'avg(r.'||z.sensor||'),';
END IF;
DBMS_OUTPUT.PUT_LINE(ausgabe);
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('FROM '||tmp_tab_name||'_ROHKORR_TAB r');
DBMS_OUTPUT.PUT_LINE('GROUP BY TRUNC(r.datum,'||hk||'DD'||hk||') ,r.r_nr');
DBMS_OUTPUT.PUT_LINE('HAVING count(TRUNC(r.datum,'||hk||'DD'||hk||')) >=
'||min_anz_rohkorrwerte_pro_tag||';');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
END LOOP;
---------------------------------------------------------------------------------------DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-Füllen der Tabellen ..._MONAT_TAB');
DBMS_OUTPUT.PUT_LINE('-- Es müssen mindestens '||min_anz_rohkorrwerte_pro_tag||'
Tageswerte pro Tag vorhanden sein.');
FOR n IN c_tab_name LOOP
tmp_tab_name := n.tab_name;
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
DBMS_OUTPUT.PUT_LINE('INSERT INTO '|| tmp_tab_name ||'_MONAT_TAB (datum, r_nr,
');
FOR z IN c_sensor LOOP -- Restliche Zeilen aus ZUORDNUNG in der 'tmp_tab_name'
steht.
IF spalte_in_tabelle(tmp_tab_name||'_MONAT_TAB',z.sensor) = TRUE THEN
SELECT MAX(sensor) INTO letzterSensor FROM zuordnung
WHERE upper(tmp_tab_name) = upper(tab_name) ORDER BY sensor;
IF UPPER(z.sensor) = UPPER(letzterSensor) THEN
ausgabe := z.sensor || ')';
ELSE
ausgabe := z.sensor || ', ';
END IF;
DBMS_OUTPUT.PUT_LINE(ausgabe);
129
Anhang
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('SELECT TRUNC(r.datum,'||hk||'MM'||hk||') ,r.r_nr , ');
FOR z IN c_sensor LOOP -- Restliche Zeilen aus ZUORDNUNG in der 'tmp_tab_name'
steht.
IF spalte_in_tabelle(tmp_tab_name||'_MONAT_TAB',z.sensor) = TRUE THEN
IF UPPER(z.sensor) = UPPER(letzterSensor) THEN
ausgabe := 'avg(r.'||z.sensor||')';
ELSE
ausgabe := 'avg(r.'||z.sensor||'),';
END IF;
DBMS_OUTPUT.PUT_LINE(ausgabe);
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('FROM '||tmp_tab_name||'_TAG_TAB r');
DBMS_OUTPUT.PUT_LINE('GROUP BY TRUNC(r.datum,'||hk||'MM'||hk||') ,r.r_nr;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
END LOOP;
---------------------------------------------------------------------------------------DBMS_OUTPUT.PUT_LINE('-******************************************************************--');
DBMS_OUTPUT.PUT_LINE('-Füllen der Tabellen ..._JAHR_TAB');
DBMS_OUTPUT.PUT_LINE('-- Es müssen mindestens '||min_anz_rohkorrwerte_pro_tag||'
Monatswerte pro Jahr vorhanden sein.');
FOR n IN c_tab_name LOOP
tmp_tab_name := n.tab_name;
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
DBMS_OUTPUT.PUT_LINE('INSERT INTO '|| tmp_tab_name ||'_JAHR_TAB (datum, r_nr, ');
FOR z IN c_sensor LOOP -- Restliche Zeilen aus ZUORDNUNG in der 'tmp_tab_name'
steht.
IF spalte_in_tabelle(tmp_tab_name||'_JAHR_TAB',z.sensor) = TRUE THEN
SELECT MAX(sensor) INTO letzterSensor FROM zuordnung
WHERE upper(tmp_tab_name) = upper(tab_name) ORDER BY sensor;
IF UPPER(z.sensor) = UPPER(letzterSensor) THEN
ausgabe := z.sensor || ')';
ELSE
ausgabe := z.sensor || ', ';
END IF;
DBMS_OUTPUT.PUT_LINE(ausgabe);
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('SELECT TRUNC(r.datum,'||hk||'YY'||hk||') ,r.r_nr , ');
FOR z IN c_sensor LOOP -- Restliche Zeilen aus ZUORDNUNG in der 'tmp_tab_name'
steht.
IF spalte_in_tabelle(tmp_tab_name||'_JAHR_TAB',z.sensor) = TRUE THEN
IF UPPER(z.sensor) = UPPER(letzterSensor) THEN
ausgabe := 'avg(r.'||z.sensor||')';
ELSE
ausgabe := 'avg(r.'||z.sensor||'),';
END IF;
DBMS_OUTPUT.PUT_LINE(ausgabe);
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE('FROM '||tmp_tab_name||'_MONAT_TAB r');
DBMS_OUTPUT.PUT_LINE('GROUP BY TRUNC(r.datum,'||hk||'YY'||hk||') ,r.r_nr;');
DBMS_OUTPUT.PUT_LINE('COMMIT;');
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
END LOOP;
---------------------------------------------------------------------------------------EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('-- Fehler: Exception OTHERS in spool_FEHL_INV_TAB.sql.');
IF c_sensor%ISOPEN THEN
CLOSE c_sensor;
END IF;
IF c_tab_name%ISOPEN THEN
CLOSE c_tab_name;
END IF;
END;
/
COMMIT;
SET FEEDBACK ON;
SPOOL OFF;
130
Anhang
Skript 31: UMGEBUNGSTABELLEN.SQL
----------------------------------------------------------------------------------------- Datei: UMGEBUNGSTABELLEN.SQL
-- Erstellt: 06.10.2000
-- Beschreibung:
-- Anlegen verschiedener Tabellen für die ZUB-Datenbank.
-- Die Tabellen werden im TABLESPACE d:\zub_db\db_indx\Messdaten.ora.
-- die Indexe und Constraints unter d:\zub_db\db_indx\Indxzub.ora angelegt
-- Änderungen:
------------------------------------------------------------------------------------------- Beschreibung siehe Skript ZUORDNUNG.SQL
DROP TABLE ZUORDNUNG;
COMMIT;
CREATE TABLE ZUORDNUNG (
HW_ADR VARCHAR2(10),
R_NR
VARCHAR2(5),
SENSOR VARCHAR2(20),
FORMAT VARCHAR2(1) NOT NULL,
TAB_NAME
VARCHAR2(30),
MINWERT NUMBER(6,2) NOT NULL,
MAXWERT NUMBER(6,2) NOT NULL)
TABLESPACE ZUB_DATEN
STORAGE (
INITIAL 200K
NEXT
50K
MINEXTENTS 1
MAXEXTENTS 300
)
PARALLEL (DEGREE 5)
/
COMMIT;
ALTER TABLE ZUORDNUNG ADD CONSTRAINT pkZuordnung PRIMARY KEY (HW_ADR, R_NR, SENSOR,
TAB_NAME)
USING INDEX TABLESPACE INDX
STORAGE (
INITIAL 100K
NEXT
50K
MINEXTENTS 1
MAXEXTENTS 300
)
ENABLE
/
COMMIT;
-- wird von der Funktion zuordnung_pruefen gefüllt mit einem Fehlerflag.
-- Ist es ungleich 0, werden keine Datentabellen angelegt oder verändert.
-- Die Tabelle wird von db_tabellen_anlegen.sql abgefragt.
DROP TABLE ZUORDNUNG_GEPRUEFT;
COMMIT;
CREATE TABLE ZUORDNUNG_GEPRUEFT (
FLAG NUMBER(2)
)
TABLESPACE ZUB_DATEN
/
COMMIT;
-- Hier werden die Anhaengsel (Suffix) der verschiedenen Datenbanktabellen
-- festgelegt.
DROP TABLE Anhang;
COMMIT;
CREATE TABLE Anhang (
anhang VARCHAR2(30),
CONSTRAINT pkAnhang PRIMARY KEY (Anhang) USING INDEX TABLESPACE INDX ENABLE
)
TABLESPACE ZUB_DATEN
/
131
Anhang
COMMIT;
-- Diese Tabelle gibt an, wann ZEITTAB mit weiteren Datumswerten gefüllt wird.
DROP TABLE Zeittab_fuellen;
COMMIT;
CREATE TABLE Zeittab_fuellen(
Jahr
DATE NOT NULL
)
TABLESPACE ZUB_DATEN
/
COMMIT;
-- Hier wird eine Datumstabelle mit 6 min. Intervallen als Referenzdatums angelegt.
-- Siehe Beschreibung zeitab.sql
DROP TABLE zeittab;
COMMIT;
CREATE TABLE zeittab (
ref_zeit
DATE,
CONSTRAINT pkZeittab PRIMARY KEY (ref_zeit) USING INDEX TABLESPACE INDX
STORAGE (
INITIAL 10M
NEXT
5M
MINEXTENTS 1
MAXEXTENTS 300
)
ENABLE )
TABLESPACE ZUB_DATEN
STORAGE (
INITIAL 10M
NEXT
5M
MINEXTENTS 1
MAXEXTENTS 300
)
PARALLEL (DEGREE 5)
/
COMMIT;
-- Die Fehler aus den Tabellen ..._FEHL_AUTO_ANZEIGE_TAB werden mit einem
-- Fehlercode versehen, der hier angelegt ist.
DROP TABLE Fehler_Code;
COMMIT;
CREATE TABLE Fehler_Code(
Nr
NUMBER(2),
Fehlerart
VARCHAR2(300),
CONSTRAINT pkFehler_Code PRIMARY KEY (Nr,Fehlerart) USING INDEX TABLESPACE INDX ENABLE
)
TABLESPACE ZUB_DATEN
/
COMMIT;
-- Es wird nur ein Hochkomma ' eingetragen.
-- Dieses wird für DBMS_SQL verwendet, um das Parsen einiger Befehle zu ermöglichen.
DROP TABLE Hochkomma;
COMMIT;
CREATE TABLE Hochkomma (
strich CHAR(1) NOT NULL
)
TABLESPACE ZUB_DATEN
/
COMMIT;
-- ZUB_DATEN_TMP_TAB anlegen, damit Prozeduren und Funktionen angelegt werden können.
-- In dieser Tabelle befinden sich die aktuellen Messdaten von der Leittechnik des
-- ZUB.
-- Das Skript prozedur_zub_daten_tmp_tab_anlegen.sql fügt die notwendigen Spalten an,
-- die in ZUORDNUNG referenziert sind.
DROP TABLE ZUB_DATEN_TMP_TAB;
CREATE TABLE ZUB_DATEN_TMP_TAB (
datum VARCHAR2(30),
uhrzeit VARCHAR2(30),
CONSTRAINT pkZUB_DATEN_TMP_TAB PRIMARY KEY (datum, uhrzeit) USING INDEX TABLESPACE INDX
ENABLE
)
TABLESPACE ZUB_DATEN
PARALLEL (DEGREE 5)
/
COMMIT;
132
Anhang
-- Tabelle wird in Forms gefüllt. Hieraus werden die Inversen Fehlertabellen erstellt.
DROP TABLE FEHL_TAB;
COMMIT;
CREATE TABLE FEHL_TAB (
lfd_nr
NUMBER(6),
tab_name
VARCHAR2(30) NOT NULL,
sensor
VARCHAR2(30) NOT NULL,
r_nr
VARCHAR2(5) NOT NULL,
fehler_nr
NUMBER(2)
NOT NULL,
anf_dat
DATE
NOT NULL,
end_dat
DATE,
Bearbeiter
VARCHAR2(30) NOT NULL,
Bemerkung
VARCHAR2(200))
TABLESPACE ZUB_DATEN
STORAGE (INITIAL 10M
NEXT
10M
MINEXTENTS 1
MAXEXTENTS 100)
PARALLEL (DEGREE 5)
/
COMMIT;
ALTER TABLE FEHL_TAB ADD CONSTRAINT pk_FEHL_TAB PRIMARY KEY (lfd_nr)
USING INDEX TABLESPACE INDX
STORAGE (INITIAL 5M
NEXT
5M
MINEXTENTS 1
MAXEXTENTS 200)
ENABLE
/
COMMIT;
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Tabelle für FORMS, um Änderungen zu verwerfen.
-- Erst wenn Änderungen in Forms übernommen wurden,
-- wird diese Tabelle aktualisiert.
DROP TABLE ZUORDNUNG_ALT;
COMMIT;
CREATE TABLE ZUORDNUNG_ALT
TABLESPACE ZUB_DATEN
STORAGE (
INITIAL 200K
NEXT
50K
MINEXTENTS 1
MAXEXTENTS 300
)
PARALLEL (DEGREE 5)
AS SELECT * FROM ZUORDNUNG;
COMMIT;
ALTER TABLE ZUORDNUNG_ALT ADD PRIMARY KEY (HW_ADR, R_NR, SENSOR, TAB_NAME)
USING INDEX TABLESPACE INDX
STORAGE (INITIAL
100K
NEXT
50K
MINEXTENTS
1
MAXEXTENTS
300)
ENABLE
/
COMMIT;
-- Tabellen für FORMS
DROP TABLE ZUORDNUNG_GEAENDERT;
COMMIT;
CREATE TABLE ZUORDNUNG_GEAENDERT
TABLESPACE ZUB_DATEN
STORAGE (
INITIAL 200K
NEXT
50K
MINEXTENTS 1
MAXEXTENTS 300
)
PARALLEL (DEGREE 5)
AS SELECT * FROM ZUORDNUNG;
COMMIT;
ALTER TABLE ZUORDNUNG_GEAENDERT ADD PRIMARY KEY (HW_ADR, R_NR, SENSOR, TAB_NAME)
USING INDEX TABLESPACE INDX
STORAGE (INITIAL
100K
NEXT
50K
133
Anhang
MINEXTENTS
MAXEXTENTS
1
300)
ENABLE
/
COMMIT;
-- Diese Tabelle wird 1:1 mit den Werten aus ZUORDNUNG gefüllt. In Forms
-- kann man hier den Messbereich (Minwert und Maxwert) bearbeiten.
-- Erst beim Übernehmen des neuen Messbereichs werden die Werte in ZUORDNUNG
-- eingetragen.
DROP TABLE ZUORDNUNG_MESS;
COMMIT;
CREATE TABLE ZUORDNUNG_MESS
TABLESPACE ZUB_DATEN
STORAGE (
INITIAL 200K
NEXT
50K
MINEXTENTS 1
MAXEXTENTS 300
)
PARALLEL (DEGREE 5)
AS SELECT * FROM ZUORDNUNG;
COMMIT;
ALTER TABLE ZUORDNUNG_MESS ADD PRIMARY KEY (HW_ADR, R_NR, SENSOR, TAB_NAME)
USING INDEX TABLESPACE INDX
STORAGE (INITIAL
100K
NEXT
50K
MINEXTENTS
1
MAXEXTENTS
300)
ENABLE
/
COMMIT;
-- Die Befehle, die ausgeführt wurden um den Messbereich zu ändern,
-- werden in diese Tabelle eingetragen und in Forms angezeigt.
DROP TABLE MESSBEREICH_GEAENDERT_TAB;
COMMIT;
CREATE TABLE MESSBEREICH_GEAENDERT_TAB (
nr
NUMBER(6),
Anweisung
VARCHAR2(300)
)
TABLESPACE ZUB_DATEN
STORAGE (INITIAL 500K
NEXT
500K
MINEXTENTS 1
MAXEXTENTS 50)
PARALLEL (DEGREE 5)
/
COMMIT;
ALTER TABLE MESSBEREICH_GEAENDERT_TAB ADD CONSTRAINT pk_MESS_GEAENDERT PRIMARY KEY (nr)
USING INDEX TABLESPACE INDX
STORAGE (INITIAL 100K
NEXT
100K
MINEXTENTS 1
MAXEXTENTS 50)
ENABLE
/
COMMIT;
-- Diese Tabelle wird gefüllt durch das Skript d:\zub_db\forms\fehl_auto_anzeige.sql
-- Fehler die noch nicht geprüft gelten (Check_Flag ist NULL) werden hier eingetragen
-- und angezeigt.
-- Die angezeigten Fehler, werden nach Sichtung in die Tabelle FEHL_TAB übernommen.
DROP TABLE FEHL_AUTO_ANZEIGE_TAB;
COMMIT;
CREATE TABLE FEHL_AUTO_ANZEIGE_TAB (
tab_name
VARCHAR2(30),
sensor VARCHAR2(30),
r_nr
VARCHAR2(5),
anz_fehler
NUMBER(6)
NOT NULL,
anf_dat
DATE
NOT NULL,
end_dat
DATE
NOT NULL,
fehler_nr
NUMBER(2)
NOT NULL,
check_flag
NUMBER(1)
DEFAULT NULL,
Bearbeiter
VARCHAR2(30)
DEFAULT NULL)
TABLESPACE ZUB_DATEN
STORAGE (INITIAL 10M
134
Anhang
NEXT
10M
MINEXTENTS 1
MAXEXTENTS 50)
PARALLEL (DEGREE 5)
/
COMMIT;
ALTER TABLE FEHL_AUTO_ANZEIGE_TAB ADD CONSTRAINT pk_FEHL_AUTO_ANZEIGE_TAB PRIMARY KEY
(tab_name, sensor, r_nr, anf_dat, fehler_nr)
USING INDEX TABLESPACE INDX
STORAGE (INITIAL 5M
NEXT
5M
MINEXTENTS 1
MAXEXTENTS 50)
ENABLE
/
COMMIT;
-- Bevor die Werte Checked aus FEHL_AUTO_ANZEIGE in die Tabellen
<Tab_Name>_FEHL_AUTO_TAB
-- eingetragen werden, wird geprüft, ob Fehler die noch nicht markiert wurden eventuell
-- zusätzlich betroffen sind. Dann wird die Tabelle mit den gefundenen Überschneidungen
gefüllt
-- und angezeigt.
DROP TABLE MOEGLICHE_UEBERSCHNEIDUNG_TAB;
COMMIT;
CREATE TABLE MOEGLICHE_UEBERSCHNEIDUNG_TAB
TABLESPACE ZUB_DATEN
STORAGE (INITIAL 50K
NEXT
50K
MINEXTENTS 1
MAXEXTENTS 50)
PARALLEL (DEGREE 5)
AS SELECT * FROM FEHL_AUTO_ANZEIGE_TAB
/
COMMIT;
TRUNCATE TABLE MOEGLICHE_UEBERSCHNEIDUNG_TAB;
COMMIT;
ALTER TABLE MOEGLICHE_UEBERSCHNEIDUNG_TAB ADD nr NUMBER(4) NOT NULL;
COMMIT;
ALTER TABLE MOEGLICHE_UEBERSCHNEIDUNG_TAB ADD CONSTRAINT pk_UEBERSCHNEIDUNG PRIMARY KEY
(nr)
USING INDEX TABLESPACE INDX
STORAGE (INITIAL 10K
NEXT
10K
MINEXTENTS 1
MAXEXTENTS 50)
ENABLE
/
COMMIT;
135
Anhang
Skript 32: ZEITTAB.SQL
----------------------------------------------------------------------------------------- Datei: ZEITTAB.SQL
-- Erstellt: 07.11.2000
-- Beschreibung:
-- Erstellen einer Zeittabelle für das laufende Jahr..
-- Sie enthält die zulässigen 6 min. Intervalle als Referenzzeit.
-- Mit ihr werden ungenaue Datums verbessert und fehlende Datums abgefragt.
-- Bei anlegen einer neuen Tabelle, wird dieses Jahr ab heute vor 8 Wochen eingetragen.
-- Ansonsten startet das Skript immer beim ersten Aufruf der Datenbank in einem neuen
Jahr.
-- Bem:
-- Änderungen:
-----------------------------------------------------------------------------------------SET SERVEROUTPUT ON
-- Tabelle mit 6 min Zeitintervallen anlegen.
DECLARE
i_voll
NUMBER(6) := 0; -- Test, ob überhaupt Werte in den Tabellen stehen.
sechs_min
NUMBER := 6/(24*60);
d_anfang
DATE;
d_lauf
DATE;
d_ende DATE;
d_fuellen
DATE;
---------------------------------------------------------------------------------------------------------BEGIN
DBMS_OUTPUT.ENABLE(1000000);
--SAVEPOINT datum_raumnummer_einfuegen;
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
DBMS_OUTPUT.PUT_LINE('-- SQL DATEI: ZEITTAB.SQL.');
SELECT jahr INTO d_fuellen FROM Zeittab_fuellen;
-- DBMS_OUTPUT.PUT_LINE('zeittab, jahr: ' || d_fuellen);
-- Zählen der Einträge in Zeittab
SELECT COUNT(ref_zeit) INTO i_voll FROM zeittab;
-- DBMS_OUTPUT.PUT_LINE('Die Zeittabelle enthält '|| i_voll || ' Datumswerte.');
-- Ein neues Jahr hat begonnen oder die Zeittabelle ist leer !
IF (d_fuellen < TRUNC(SYSDATE,'YYYY')) OR (i_voll = 0) THEN
-- Anfang ist 00:00 des heutigen Tages
IF i_voll = 0 THEN -- Datenbank noch nicht in Betrieb. Anfang ist heute.
SELECT TRUNC(SYSDATE,'DD')-8*7 INTO d_anfang FROM DUAL;
-DBMS_OUTPUT.PUT_LINE('-- Die Zeittabelle ist leer. Beginn der
Datumeinträge beginnt heute vor 8 Wochen.');
ELSE -- Es gibt schon Einträge, also Beginn ist Anfang des Jahres
SELECT TRUNC(SYSDATE,'YYYY') INTO d_anfang FROM DUAL;
-DBMS_OUTPUT.PUT_LINE('-- Die Zeittabelle ist gefüllt. Es wird ein
komplettes Jahr eingetragen.');
END IF;
d_lauf := d_anfang;
-- Ende ist 31.12 23:54
SELECT TRUNC(TRUNC(SYSDATE,'YYYY') + 370,'YYYY')-sechs_min INTO d_ende FROM DUAL;
-DBMS_OUTPUT.PUT_LINE('Anfang: '|| to_char(d_anfang,'dd.mm.yy hh24:mi') ||' Ende:
'|| to_char(d_ende,'dd.mm.yy hh24:mi'));
-TESTFUNKTION
-d_anfang := to_date('20.11.2000 00:00','dd.mm.yyyy hh24:mi');
-d_lauf := d_anfang;
-d_ende := to_date('02.02.2001 00:12','dd.mm.yyyy hh24:mi');
SET TRANSACTION USE ROLLBACK SEGMENT RB_BIG;
<<innen>>
LOOP
EXIT WHEN d_lauf > d_ende;
136
Anhang
INSERT INTO zeittab (ref_zeit) VALUES (d_lauf);
d_lauf := d_lauf + sechs_min;
END LOOP innen;
COMMIT;
DBMS_OUTPUT.PUT_LINE('-- Zeittabelle wurde aktualisiert von '||
to_char(d_anfang,'dd.mm.yyyy hh24:mi') ||' bis '||to_char(d_ende,'dd.mm.yyyy
hh24:mi')||'.');
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
ELSE
SELECT max(ref_zeit) INTO d_fuellen FROM zeittab;
DBMS_OUTPUT.PUT_LINE('-- Zeittabelle ist aktuell bis '||
to_char(d_fuellen,'dd.mm.yyyy hh24:mi'));
DBMS_OUTPUT.PUT_LINE('-----------------------------------------------');
END IF;
-- Updaten der Jahreswertberechnung.
UPDATE Zeittab_fuellen SET jahr = TRUNC(SYSDATE,'YYYY');
COMMIT;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('EXCEPTION: OTHERS in Zeittab.sql');
RAISE;
END;
/
COMMIT;
137
Anhang
Skript 33: ZUORDNUNG.SQL
----------------------------------------------------------------------------------------- Datei: ZUORDNUNG.SQL
-- Erstellt: 06.11.2000
-- Beschreibung:
-- Die Tabelle ZURDNUNG ist die Basis der gesamten Datenbank.
-- Sie enthält alle Verknüpfungen zwischen den Messdaten, die vom ZUB verfügbar sind
-- und den Datenbanktabellen, in denen die Messdaten geordnet werden.
-- Sie enthält:
-- Hw_Adr
Hardwareadresse: Bezeichnet die Spaltennamen aus
-der Tabelle ZUB_DATEN_TMP_TAB (dort werden die Rohdaten abgelegt)
-- R_Nr
Die Raumnummer in der der Messaufnehmer installiert ist
-- Sensor
Die Art des Sensors (z.B. T_OBERFL (Oberflächentemperatursensor)).
-Bezeichnet die Spaltennamen in den Datenbanktabellen.
-- Format
Beschreibung ob es ein Binärwert oder Analogwert ist (nur 'A' oder
'B')
-- Tab_Name Tabellenname für die Datenbank (wird später angelegt)
-In der Tabelle <Tab_Name> werden jeweils die Spalten <Sensor>
angelegt.
-Die Tabellennamen entsprechen den Informationsschwerpunkten aus
der
-entsprechenden Liste.
-- Minwert
Minimaler erlaubter Wert des Messbereiches, sonst wird der Messwert
als
-fehlerhaft markiert.
-- Maxwert
Maximaler erlaubter Wert des Messbereiches, s.o.
-- Die Verknüpfung besteht hauptsächlich aus den Spalten Hw_Adr, Tab_Name und Sensor.
-- <Hw_Adr> bezeichnet die Spaltennamen aus der täglichen Messdatentabelle
-- ZUB_DATEN_TMP_TAB.
-- Aus der Beziehung <Tab_Name> und <Sensor> kann die <Hw_Adr> eindeutig einer Tabelle
aus
-- der Datenbank mit der Spalte <Sensor> zugeordnet werden.
-- Bemerkung: <BeipielWert> wird gelesen als "Inhalt der Spalte BeispielWert".
-- Änderungen:
-----------------------------------------------------------------------------------------TRUNCATE TABLE ZUORDNUNG;
-- Initialisierung der Tabelle ZUORDNUNG
-- Hier sollten neue Sensoren eingetragen werden und alte gelöscht werden,
-- um bei einer neuen Initialisierung der Datenbank den aktuellen Stand
-- zur Verfügung zu haben.
INSERT INTO ZUORDNUNG VALUES ('H00100', '0_01',
'T_I',
10,50);
INSERT INTO ZUORDNUNG VALUES ('H00101', '0_01',
'VENTIL_A',
INSERT INTO ZUORDNUNG VALUES ('H00102', '0_01',
'VENTIL_B',
INSERT INTO ZUORDNUNG VALUES ('H00103', '0_01',
'VENTIL_C',
INSERT INTO ZUORDNUNG VALUES ('H00104', '0_01',
'T_OBERFL0',
10,50);
INSERT INTO ZUORDNUNG VALUES ('H00105', '0_01',
'T_OBERFL1',
10,50);
INSERT INTO ZUORDNUNG VALUES ('H00106', '1_02',
'T_I',
10,50);
INSERT INTO ZUORDNUNG VALUES ('H00107', '1_02',
'VENTIL_A',
INSERT INTO ZUORDNUNG VALUES ('H00108', '1_02',
'VENTIL_B',
INSERT INTO ZUORDNUNG VALUES ('H00109', '1_02',
'VENTIL_C',
INSERT INTO ZUORDNUNG VALUES ('H00110', '1_02',
'T_OBERFL0',
10,50);
INSERT INTO ZUORDNUNG VALUES ('H00111', '1_02',
'T_OBERFL1',
10,50);
INSERT INTO ZUORDNUNG VALUES ('H00112', '1_02',
'T_OBERFL0',
10,50);
INSERT INTO ZUORDNUNG VALUES ('H00113', '1_02',
'T_OBERFL1',
10,50);
INSERT INTO ZUORDNUNG VALUES ('H00114', '1_02',
'T_OBERFL2',
10,50);
select count(*) AnzahlWerteinZuordnung from zuordnung;
select * from zuordnung order by tab_name, sensor, r_nr, hw_adr;
'A',
'STDR',-
'B',
'B',
'B',
'A',
'STDR',0,1);
'STDR',0,1);
'STDR',0,1);
'STDR',-
'A',
'STDR',-
'A',
'STDR',-
'B',
'B',
'B',
'A',
'STDR',0,1);
'STDR',0,1);
'STDR',0,1);
'STDR',-
'A',
'STDR',-
'A',
'MESSR',-
'A',
'MESSR',-
'A',
'MESSR',-
138
Anhang
9.2 CD-ROM
9.2.1 Diese Ausarbeitung
9.2.2 PL/SQL Skripte, Eingabemaske unter ORACLE Forms
139
Herunterladen