Il task da eseguire viene definito attraverso uno script in linguaggio Visual Basic.NET (VB.NET).
Nello script è possibile utilizzare primitive specifiche per il trasferimento dati da altri database, che nelle release precedenti alla 2015.17.2c era necessario programmare attraverso il servizio QDaemon il quale era basato sulla piattaforma client/server, facendo uso del linguaggio dBase.
Le primitive consentono di specificare la definizione della mappatura dei campi della tabella da trasferire in una modalità del tutto simile a quella utilizzata nella precedente versione di QDaemon, rendendo anche più semplice la migrazione di script esistenti alla piattaforma web.
Tale definizione della mappatura viene effettuata attraverso l’oggetto QDaemonTableDef.
Una volta assegnato l’oggetto QDaemonTableDef, è necessario richiamare l’apposita primitiva di importazione, che ha la seguente sintassi:
QDaemonImportTable(<oggetto database>,<nome tabella>,<oggetto TableDef>) , dove:
- <oggetto database> è l’oggetto contenente il database rappresentato dalla variabile DB,
- <nome tabella> è una stringa contenente un nome convenzionale assegnato alla tabella/file da importare e può essere assegnato arbitrariamente,
- <oggetto QDaemonTableDef> e l’oggetto di tipo QDaemonTableDef contenente la definizione della tabella/file da importare e la mappatura dei campi.
La primitiva QDaemonImportTable registra gli eventi sulla tabella LOGDOC con CODDOC=’QDAEMON’. Per verificare l’esito delle importazioni ed eventuali errori si può utilizzare la funzionalità Consultazione LOG QualiWare Server Daemon selezionando l’opzione “Qdaemon”.
Note sui CodeBlock
I CodeBlock possono essere utilizzati sia nella definizione dei campi sia nella proprietà AfterSave. Le sintassi da utilizzare sono però diverse.
Nel primo caso, il CodeBlock può essere scritto in due modi:
.campi("INVOICE_MONTH")=Function (oFlds,oFldsQ) val(oFlds("INVOICE_MONTH").value)
oppure
.campi("INVOICE_MONTH")=Function (oFlds,oFldsQ) return val(oFlds("INVOICE_MONTH").value) End Function
La differenza fra le due sintassi consiste nel fatto che la prima può essere usata se il calcolo consiste in una sola funzione, la quale può essere specificata direttamente dopo la parola chiave “Function” senza necessità di specificare “Return”. La seconda invece deve essere utilizzata quando il calcolo richiede più istruzioni, e dovrà essere utilizzata la parola chiave “Return” per restituire il risultato.
Si noti che la specifica del parametro “oFldsQ” non è obbligatoria.
Nel caso della proprietà AfterSave, il CodeBlock non deve ritornare un valore, e la sintassi da utilizzare in quel caso sarà come la seguente:
tabella.AfterSave=Sub (oTbl) oTbl.replace("DESCREXT",oTbl.rowset.fields("DESCRIZION").value) oTbl.saverecord() End Sub
Esempi
Di seguito sono riportati alcuni esempi di script di importazione.
Importazione da una query, con AfterSave
dim tabella as new QDaemonTableDef tabella.gest_sql="select 'Z'+CODICE as CODICE, DESCRIZION, UNMIS, TIPO, UNCAMP from ARTIC where CODICE like 'ZZZ%'" tabella.q95_name="ARTIC" tabella.keys=new dbarray("CODICE") with tabella .campi("CODICE")="CODICE" .campi("DESCRIZION")="DESCRIZION" .campi("UNMIS")="UNMIS" .campi("TIPO")="TIPO" .campi("UNCAMP")=Function (oFlds) 1 end with tabella.AfterSave=Sub (oTbl) oTbl.replace("DESCREXT","AfterSave") oTbl.saverecord() End Sub QDaemonImportTable(DB,"ARTIC",tabella)
Importazione da file CSV delimitato da virgola, senza intestazioni e con doppi apici
dim tabella as new QDaemonTableDef tabella.gest_name="\\server\csv\Turnover.txt" tabella.Gest_Separator="Delimited(,)" tabella.gest_ColumnNames=new dbarray("INVOICE_YEAR","ITEM_GROUP","PRODUCT_LINE","INVOICE_MONTH","COUNTRY_CODE","CUSTOMER_CODE","CUSTOMER_NAME","ITEM_CODE","ITEM_DESCRIPTION","QUANTITY","TURNOVER","COST_OF_SALES","MARGIN","EXTERNAL_SALES_REP","BUSINESS_UNIT_CODE","BUSINESS_UNIT_NAME") tabella.q95_name="P_TURNOVER" tabella.gest_CharacterSet="ANSI" tabella.keys=new dbarray("INVOICE_YEAR","INVOICE_MONTH","CUSTOMER_CODE","ITEM_CODE","PROV") with tabella .campi("INVOICE_YEAR")= (Function (oFlds) val(oFlds("INVOICE_YEAR").value)) .campi("ITEM_GROUP")="ITEM_GROUP" .campi("PRODUCT_LINE")="PRODUCT_LINE" .campi("INVOICE_MONTH")=Function (oFlds,oFldsQ) val(oFlds("INVOICE_MONTH").value) .campi("COUNTRY_CODE")="COUNTRY_CODE" .campi("CUSTOMER_CODE")=Function (oFlds) "C"+substr2(oFlds("CUSTOMER_CODE").value,4) .campi("CUSTOMER_NAME")="CUSTOMER_NAME" .campi("ITEM_CODE")="ITEM_CODE" ' Chiave .campi("ITEM_DESCRIPTION")="ITEM_DESCRIPTION" .campi("QUANTITY")=Function (oFlds) val(oFlds("QUANTITY").value) .campi("TURNOVER")=Function (oFlds) val(oFlds("TURNOVER").value) .campi("COST_OF_SALES")=Function (oFlds) isnull(val(oFlds("COST_OF_SALES").value),0) .campi("MARGIN")=Function (oFlds) isnull(val(oFlds("MARGIN").value),0) .campi("EXTERNAL_SALES_REP")="EXTERNAL_SALES_REP" .campi("PROV")=Function () 0 end with QDaemonImportTable(DB,"P_TURNOVER",tabella)
Importazione da file CSV, delimitato da Tab e con intestazioni
dim tabella as new QDaemonTableDef tabella.gest_name="\\server\csv\artic.csv" tabella.Gest_Separator="TabDelimited" tabella.q95_name="ARTIC" tabella.keys=new dbarray("CODICE") with tabella .campi("CODICE")="CODICE" .campi("DESCRIZION")="DESCRIZION" .campi("UNMIS")="UNMIS" .campi("TIPO")=Function (oFlds) val(oFlds("TIPO").value) .campi("UNCAMP")=Function (oFlds) val(oFlds("UNCAMP").value) end with QDaemonImportTable(DB,"ARTIC",tabella)
Importazione da file CSV delimitato da Tab e senza intestazioni
dim tabella as new QDaemonTableDef tabella.gest_name="\\server\csv\Turnover.txt" tabella.Gest_Separator="TabDelimited" tabella.gest_ColumnNames=new dbarray("INVOICE_YEAR","ITEM_GROUP","PRODUCT_LINE","INVOICE_MONTH","COUNTRY_CODE","CUSTOMER_CODE","CUSTOMER_NAME","ITEM_CODE","ITEM_DESCRIPTION","QUANTITY","TURNOVER","COST_OF_SALES","MARGIN","EXTERNAL_SALES_REP","BUSINESS_UNIT_CODE","BUSINESS_UNIT_NAME") tabella.q95_name="P_TURNOVER" tabella.keys=new dbarray("INVOICE_YEAR","INVOICE_MONTH","CUSTOMER_CODE","ITEM_CODE","PROV") with tabella .campi("INVOICE_YEAR")= (Function (oFlds) val(oFlds("INVOICE_YEAR").value)) ' Chiave .campi("ITEM_GROUP")="ITEM_GROUP" .campi("PRODUCT_LINE")="PRODUCT_LINE" .campi("INVOICE_MONTH")=Function (oFlds,oFldsQ) val(oFlds("INVOICE_MONTH").value) ' Chiave .campi("COUNTRY_CODE")="COUNTRY_CODE" .campi("CUSTOMER_CODE")=Function (oFlds) "C"+substr2(oFlds("CUSTOMER_CODE").value,4) ' Chiave .campi("CUSTOMER_NAME")="CUSTOMER_NAME" .campi("ITEM_CODE")="ITEM_CODE" ' Chiave .campi("ITEM_DESCRIPTION")="ITEM_DESCRIPTION" .campi("QUANTITY")=Function (oFlds) val(oFlds("QUANTITY").value) .campi("TURNOVER")=Function (oFlds) val(oFlds("TURNOVER").value) .campi("COST_OF_SALES")=Function (oFlds) isnull(val(oFlds("COST_OF_SALES").value),0) .campi("MARGIN")=Function (oFlds) isnull(val(oFlds("MARGIN").value),0) .campi("EXTERNAL_SALES_REP")="EXTERNAL_SALES_REP" .campi("PROV")=Function () 0 end with QDaemonImportTable(DB,"P_TURNOVER",tabella)
Importazione di dati tramite WebService
' Il seguente frammento di codice fornisce un esempio di come sia possibile acquisire informazioni da un ' un servizio esterno di rilevazione dati tramite la chiamata ad un WebService utilizzando una URL che restituisce una stringa XML. ' Nella fattispecie, viene utilizzato il Web Service messo a disposizione dal sistema di monitoraggio dei ' pannelli fotovoltaici SolarEdge ) ' L'output è il seguente: ' <series> ' <timeUnit>HOUR</timeUnit> ' <unit>Wh</unit> ' <measuredBy>INVERTER</measuredBy> ' <values> ' <dateValue> ' <date>2017-05-08 00:00:00</date> ' <value>0.0</value> ' </dateValue> ' .... ' </values> ' </series> ' I dati vengono recuperati su base giornaliera (per il giorno corrente) e memorizzati nella tabella IOTLOG Dim Q as new QWTable Q.Database=DB Q.sql="select * from IOTLOG" Q.allowallrecords=false Q.active=true Dim d as string=ltrim(dbase.str(Today.Year))+"-"+ltrim(dbase.str(Today.Month))+"-"+ltrim(dbase.str(Today.Day)) Dim url As String = "https://monitoringapi.solaredge.com/site/349661/energy.xml?timeUnit=HOUR&endDate="+d+"&startDate="+d+"&api_key=KDZ46QJYX2HQPIVPJY7KX3R9HA7ULNRG" Dim webClient As New System.Net.WebClient Dim result As String = webClient.DownloadString(Url) ' Recupero della risposta Dim response = System.XML.Linq.XElement.Parse(result) for each el as System.XML.Linq.Xelement in response.LastNode.Nodes ' Il LastNode è "Values", e ne estrae tutti i nodi ' Il quarto nodo è quello dei Values Dim Data As String Dim Valore as String Data=Ctype(el.FirstNode,System.Xml.Linq.Xelement).Value dim da as System.datetime=System.Datetime.parse(data) Valore=Ctype(el.LastNode,System.Xml.Linq.Xelement).Value if Valore<>"null" if not q.rowset.findkey(da,"SOLAR","SITE1") q.beginappend() q.replace("DATA",da) q.replace("DEVICENAME","SOLAR") q.replace("SENSORNAME","SITE1") End If q.replace("VALUE",val(Valore)) q.saverecord() End If next Q.active=false