Beispiele
BEISPIEL
dpQuery("SELECT ALERT '_alert_hdl.._value' FROM '*' WHERE _DPT =\ "ExampleDP_Float\" ", tab);
Beachten Sie, dass die SQL-Abfrage auf eine Zeile definiert werden muss, obwohl es hier auf zwei Zeilen aufgeteilt ist.
dpQuery("SELECT '_online.._value' FROM '*' WHERE (_ELC==DPEL_FLOAT) & '_online.._value > 1");
In diesem Beispiel sollte aus Performancegründen der Datenpunkt-Ausdruck direkt hinter dem FROM angegeben werden, da so das Auslesen aller Datenpunktwerte entfallen kann.
BEISPIEL
Dieses Query liest den Online-Wert und den Zeitpunkt, wann dieser Online-Wert gesetzt wurde aus. Hierzu
werden alle DPs abgefragt, deren Blätter vom Typ "bool" sind. Die verwendbaren Konstanten sind unter Datentypen von Datenpunktelementen vermerkt.
select = "SELECT '_online.._stime','_online.._value' FROM '*' WHERE _ELC ==DPEL_BOOL";
Hier werden nur die Blattenden ausgewählt UND das Userbit 7 muss gesetzt sein.
select = "SELECT '_online.._stime','_online.._value' FROM '*' WHERE _LEAF AND '_online.._userbit7' == 1";
Wenn der DPTyp "Query" heißt, werden alle Werte wie im ersten Teil angezeigt, ausgegeben. (Als BSP dafür, dass auch vorn komplette DP-Teile mit z.B. EL angegeben werden können.)
select = "SELECT 'Text1:_online.._value','Text2:_online.._value','Text3:_online.._value' FROM '*' WHERE _DPT = \"Query\" ";
Es können nur Konfigs abgefragt werden, die der Eventmanager verwaltet! Das sind Benutzerwertebereich, WinCC OA Wertebereich (_u_range, _pv_range), Berechtigung (_auth), DP Funktionen (_dp_fct), Ersatzwert (_default), Meldebehandlung (_alert_hdl), Meldeklasse (_alert_class), Online-, Originalwert (_online, _original) und Sperre (_lock).
In den nachstehenden Beispielen werden verschiedene Datenpunkte verwendet. Neben mld_float vom Typ ExampleDp_Float und mld_bit (ExampleDp_Bit) kommen folgende weitere Datenpunkte vor:
Der Datenpunkt Gasleitung1 ist vom selbst angelegten Datenpunkttyp Gasleitung.
Die Datenpunkte Motor1 und Motor2 sind vom selbst angelegten Datenpunkttyp Motor.
Abfrage nach aktuellen Daten
Mit dem Befehl:
SELECT '_online.._value' FROM 'mld_float.**'
werden die aktuellen Daten abgefragt, wie sie zum Beispiel auch über dpGet zu bekommen wären. In diesem speziellen Fall würden alle aktuellen Daten gefunden, die die Struktur "mld_float.:_online.._value" besitzen (und sich im aktuellen System befinden).
Aus dem Control-Script ist dieser Befehl wie folgt zu verwenden:
dpQuery ("SELECT '_online.._value' FROM 'mld_float.**'", tab);
Der Query-Befehl gibt als Ergebnis eine zweidimensionale Matrix zurück. Diese wird hier der Variablen tab übergeben. Da nicht bekannt ist, von welchem Format die Daten der Matrix sein werden, wird die Variable tab als Typ dyn_dyn_anytype deklariert.
Beim Auslesen ist zu beachten, dass die angeforderten Daten in der zweiten Spalte abgelegt werden. Wegen einer automatisch hinzugefügten Kopfzeile ist der erste Wert in der Zelle [2][2] zu finden, der nächste in Zelle [3][2], ..., [n][2] (mit n e N+{ 2 £ n; n = letzte Zeile}).
Abfrage nach archivierten Meldungen
Wie schon oben erwähnt, sind die verwalteten Werte in verschiedene Datenbankbereiche unterteilt. Im Control wird mit SELECT auf den Bereich mit den "normalen" Werte geschaltet. Durch die Angabe SELECT ALERT werden die gespeicherten Meldungen ausgelesen.
dpQuery ("SELECT ALERT ’_alert_hdl..value’ FROM 'mld_bit'", tab);
Bei Eintrag der DP-Ebene (hier: "mld_bit") muss keine Angabe über die Tiefe (".**") getroffen werden: diese werden vom Control ggf. ergänzt (es kann also das ".**"entfallen. Hingegen muss der Datenpunktteil ab Konfigebene (KF.DT.AT) immer angegeben werden.
Nur auf Änderungen reagieren
Bei den Query-Funktionen besteht, wie bei der Standard-Control-Programmierung, eine Möglichkeit, nur die Änderungen der Werte auszulesen. Mit einer dpQueryConnect-Funktion kann dies wie folgt realisiert werden:
main(mapping event)
{
dpQueryConnectSingle("workfunc", TRUE, "EV_connect_single", "SELECT '_online.._value'FROM 'ExampleDP_Arg*'");
}
workfunc(string ident, dyn_dyn_anytype result)
{
DebugN(ident, result);
}
Mit der oberen Zeile wird eine Verbindung zu allen Online-Werten der Datenpunkte hergestellt, die mit mld_ beginnen.
Bei einer Änderung wird hier die Funktion workfunc aufgerufen und dabei zwei Parameter übergeben. In letzterem werden die Ergebnisse der Abfrage geschrieben. Bei dem Auslesen der Informationen besteht ein Unterschiede zwischen Daten und Meldungen, wie im Kapitel "Queries" zu lesen ist.
Besteht die Notwendigkeit, an die Subroutine workfunc eigene Werte zu übergeben, ist dies nicht über den Funktionsaufruf möglich, da hier nur die zwei Übergabeparameter "ident" und "result" erwartet werden. Dennoch können unter Verwendung globaler Variablen eigene Daten in die Unterfunktion gelangen.
Der zweite Eintrag in der Hauptfunktion (hier TRUE) sagt aus, ob in dem Moment des Ankoppelns ein gesamtes Abbild vom aktuellen Zustand der Datenbank übermittelt werden soll.
Funktionsablauf eines SingleConnect...ALERT SINGLE
Nur, wenn einer der angemeldeten Werte den jeweiligen gültigen Wertebereich verlässt oder in diese Grenzen wiederkehrt, wird ein Wert geschrieben. Bei Start mit einem gültigen Wert hingegen wird kein Wert geschrieben. :
BEISPIEL
Für die folgenden Beispiele findet wieder der Datenpunkt ExampleDP_Arg_ Verwendung. Die Auflösung der Wildcardadressen bis auf Elementebene kann der dortigen Tabelle entnommen werden.
main(mapping event)
{
dpQueryConnectSingle("workfunc", TRUE, "EV_connect_single", "SELECT '_online.._value'FROM 'ExampleDP_Arg*'");
}
workfunc(string ident, dyn_dyn_anytype result)
{
DebugN(result);
}
BEISPIEL
Hier werden die Alarme aller DPs abgefragt und in einer Zeile angezeigt.
/* SimpleCtrlScriptStart {invalid} SimpleCtrlScript {SetValue} object {Text1} attribute
{backCol} value {Red} SimpleCtrlScriptEnd */
main()
{
int rc;
setValue("Text1","backCol","Red");
rc = dpQueryConnectSingle( "work", 0, "ident", "SELECT ALERT SINGLE '_alert_hdl.._value'
FROM '*'" ); DebugN ("nach QueryConnectSingle: ", rc );
}
work( string ident, dyn_dyn_anytype val )
{
int i;
DebugN( "Work: ", dynlen( val ) );
for (i = 2; i <dynlen(val ); i++ )
DebugN( "value: ", i, val[i][1], val[i][2] );
}
Alle Blattknoten von Datenpunkten, und davon alle Originalwerte
dpQuery("SELECT '_original.._value' FROM 'Motor1' WHERE _LEAF", tab);
Motor1 wird intern auf Motor1.** erweitert, um alle Elemente des Datenpunktes zu
liefern.Dann wird von allen Elementen das Attribut _original.._value ausgewählt.
Im dritten Schritt wird dieses Ergebnis noch auf die Bedingungen des Query überprüft. Hier werden alle momentanen Werte der einzelnen Elemente (Motor1.Drehzahl:_original.._value und Motor1.Störung:_original.._value) vom Datenpunkt Motor1 ausgegeben.
Werden z.B. die letzten 100 Zeilen aller Datenpunkte aus der Datenbank gesucht, so muss die Abfrage anders formuliert werden:
dpQuery("SELECT '_original.._value', '_original.._stime' FROM '*' SORT BY 2 LAST 100", tab);
Bei dieser Abfrage ist es wichtig, die Zwischentabelle zu sortieren, um wirklich die letzten 100 Werte zu bekommen. Generell ist die Reihenfolge der Abfrageergebnisse nämlich unbestimmt. Wenn viele Datenpunkte in der Datenbank vorhanden sind, so verursacht dies das Anlegen einer großen Zwischentabelle. In diesem Fall ist es besser, eine TIMERANGE-Funktion mit dem entsprechenden Bonus-Parameter aufzurufen. Um also die letzten 100 Werte zu bekommen, übergibt man
dpQuery("SELECT '_original.._value' FROM 'ExampleDP_Arg1' TIMERANGE(\"NOW\", \"2020.06.10 17:11:00.000\",1,100)SORT BY 1", tab);
Hier wird für den Startzeitpunkt der jetzige angegeben, die Stoppzeit wird nicht genannt. Die letzten 100 Werte werden aktualisiert und nach der Zeit sortiert.
Die aktuelle Drehzahl aller Motoren einer Anlage
Dazu setzen wir voraus, dass alle Motoren-Datenpunkte vom gleichen Datentyp Motor abgeleitet sind, der ein Element Drehzahl enthält. Die Abfrage lautet:
dpQuery("SELECT 'wert' FROM '*.Drehzahl:_original..' WHERE _DPT = \"Motor\"", tab);
Eine weitere Möglichkeit ist folgende:
dpQuery("SELECT '_original.._value', '_original.._stime' FROM 'Motor*.Drehzahl'", tab);
Neben der Vorraussetzung, dass alle Motoren vom gleichen Typ sein müssen, muss gewährleistet sein, dass auch neu anzulegende Datenpunkte sich an die Motor... Namensgebung halten. Zusätzlich wird hier die Quellzeit mit ausgegeben.
Generell ist bei einer Abfrage vom oben genannten Typ die zweite Version zu bevorzugen, da bei Variante eins zunächst alle Datenpunkte mit einem Element Drehzahl ausgelesen werden und erst in einem weiteren Schritt die Begrenzung auf den Datenpunkt MOTOR erfolgt.
Liste von Userwertebereichen bestimmter Elemente
Mit der nachfolgenden Abfrage können verschiedene Attribute (hier: "min" und "max") von bestimmten Datenpunkten ermittelt werden:
dpQuery("SELECT 'min', 'max' FROM 'Gasleitung1.**:_pv_range'", tab);
Als Ergebnis erhält man hier die entsprechenden Grenzwerte des Config "WinCC OA Wertebereich". Die Detail-Ebene wird intern als 0 ergänzt ('Gasleitung1.**:_pv_range.0.min').