Datenbankverbindungen in Kettle-Dateien
Nach der Installation von Spoon ist folgendes zu beachten: Beim Bearbeiten von Kettle Dateien mit Spoon wird die jeweilige dbconnection der lokalen "eduetl"-Datenbank in den KTR/KJB Dateien gespeichert. Vor dem Commit ins GIT muss diese entfern werden.
mit Groovy
Dafür gibt es ein Groovy-Script im Kernmodul in superx/scripts/groovy/copy_kettlejob.groovy. Dieses wiederum benötigte groovy im PATH, daher muss man
- groovy installieren, z.B. in /home/superx/tools/groovy/groovy-2.4.10
- groovy in den PATH mit aufnehmen:
PATH=$PATH:/home/superx/tools/groovy/groovy-2.4.10/bin export PATH
Dann legt man sich einen lokalen "Arbeitsorder" an, der nicht im git liegt, und erzeugt ein Unterverzeichnis für die temp. Dateien. Hier das Beispiel eines Jobs im SVA Modul mit dem Unterverzeichnis sap_hr_sva
Das Script wird dann so aufgerufen :
groovy ~/git/superx/scripts/groovy/copy_kettlejob.groovy --strip-connections $SVA_PFAD/etl/sap_hr/sap_hr_sva.kjb sap_hr_sva
Die kjb-/ktr Dateien werden aus dem git kopiert ins Unterverzeichnis sap_hr_sva, und dort werden die Connections entfernt. Wenn man die Entwicklung beendet hat, kann man diese Dateien ins richtige git Verzeichnis kopieren und committen:
cp -a sap_hr_sva/* $SVA_PFAD/etl/sap_hr
xmlstarlet
Komfortabler geht es mit xmlstarletAnwendung Hier ein Script removeConnection.x
#!/bin/bash #sudo apt install xmlstarlet for file in *.kjb *.ktr; do [ -f "$file" ] || continue # Überspringt, falls keine Dateien existieren ##durch das && wird bewirkt, dass bei Fehler von xmlstarlet Originaldatei nicht überschrieben wird ## Connection-Knoten, bei denen auch die aufgeführten Unterknoten existieren, werden enfernt xmlstarlet ed -d "//connection[name and server and type and access and database]" "$file" > "${file}.tmp" && mv "${file}.tmp" "$file" done
Grundsätzliches zum Datenflow
Nach einer SQL-Aktion mit dem Löschen von Daten muss man einen Warten Step einbauen.Ab einem bestimmten Step kann man in mehrere folgende Steps verzweigen, denen allen der gesamt Flow zur Verfügung steht.
(Methode "Copy" auswählen, nicht "Distribute").
Komplexes Beispiel
siehe unter Aus Excel in Datenbank schreiben / Werte nachtragen (Beispiel erst Kosten- dann Beschäftigungsstellen)
Beispiel db/module/sva/etl/sap_hr/sap_load_stamm_beschstellen.ktr Step Insert sva_inst_neu
Informationen zu einzelnen Steps
Update Step
siehe "Aus Exceldatei in Datenbank schreiben / Aus mehreren Sheets
Filter Step (ähnlich SQL where)
siehe unter "Aus Exceldatei in Datenbank schreiben / Erst bestimme Zeilen rausfiltern und dann Update
Beispiel db/module/sva/etl/sap_hr/sap_load_pgd_eintrittssdatum.ktr
Man kann auch mehrere Bedingungen angeben, dazu klickt man auf das kleine rot umrandete Plus Zeichen.
Man sollte darauf achten, dass bei Verknüpfung zu folgenden Schritten nicht "Main Ouput", sondern "Result is TRUE" ausgewählt wird, dann wird im Screenshot bei "send true to data step" der entsprechende Schritt eingetragen.
Man erkennt auch daran, dass grünes Häkchen an Verbindungslinie.
Wenn ein Filter Rows mit True die Ausgabe an mehrere Schritte liefern sollen, geht das nicht, man kann immer nur an einen Schritt liefern.
Andere Schritte bekommen nicht das "True" Häkchen und machen einfach nichts!
Daher muss man einen "Dummy-Schritt" einfügen:
sap_load_stellen
Group by Step
Max/Min Ermitteln - siehe "Aus Exceldatei in Datenbank schreiben / Max(Spalte) ermitteln und nachtragen (Beispiel db/module/sva/etl/sap_hr/sap_load_pgd_austrittsdatum.ktr)
Kann noch mehr auch ersten/letzen Wert ermitteln, interessant für Gültigkeiten
siehe Bei mehreren Datenzeilen Neuste raussuchen (Gültigkeit) ( Beispiel db/module/sva/etl/sap_hr/sap_load_pgd_wohnort.ktr)
Standardmäßig müssen Datenzeilen vorher sortiert sein, damit es richtig klappt, man kann "Fehlfunktion" aber nutzen, um z.B. "Zeitscheiben" zu ermitteln, s.u.
Select Values (Felder umbenennen/Datentyp ändern/ Feld kopieren)
Hiermit kann man Feldnamen umbennen oder auch Datentypen ändern im Reiter "Metadata"
siehe auch unter "Aus Exceldatei in Datenbank schreiben / Aus String Jahr "2000" ein Datum machen (1.1.2000)
Beispiel db/module/sva/etl/sap_hr/sap_load_pgd_habil.ktr
Felder, die im weiteren benötigt werden, müssen einfach aufgeführt werden. z.B: Einfach "Planstelle" bei "select&alter" unter Fieldname - andere Spalten leer.
Es werden nur die aufgeführten Felder weiter im Stream übergeben (vergl. sva/etl/sap_hr/sap_load_stellen.ktr)
Auch Felder können kopiert werden, dazu zweimal aufführen, als Feld selbst und mit neuem Namen,
Beispiel TarifGruppe (TrfGr) soll standardmäßig auch als Name genommen werden (mit einem generateRows Step aber eigener Name für Schlüssel _unb)
Vergl. sap_load_stamm_bvl
User Defined Java Expression
Siehe Beispiel unter "Aus Excel in Datenbank schreiben" / Den kleineren/größeren Wert aus zwei Spalten ermitteln
weiterhin Beispiel unter "Aus Excel in Datenbank schreiben / Feld wird zu Decimalzahl 1020,0 transformiert soll aber String sein
Get Value from Sequence
Kann man z.B. für erzeugen einer künstlichen ID gebrauchen, siehe unter Aus Excel in Datenbank schreiben / Eine Künstliche ID erzeugen
db/module/sva/etl/sap_hr/sap_load_stamm_laufbahn.ktr.
Um die erzeugte ID aus der Datenbank auszulesen nutzt man Database Lookup
Database Lookup
Kann z..B: verwendet werden, um eine ID aus der Datenbank zu holen.
Microsoft Excel Input
Der "Microsoft Excel Input" Step kann Excel Dateien lesen und weiterverarbeiten.
Microsoft Excel Input Reiter Files
Wählen Sie beim "Spread Sheet type (engine)" am besten "Excel 2007 XLSX (Apache POI)". Grund: diese Importfunktion unterstützt sowohl "*.xls" als auch "*.xlsx".
Wenn Sie z.B. alle Excel-Dateien in einem Verzeichnis einlesen wollen, geben Sie die Wildcards an:
.*\.xls .*\.xlsx
Damit lädt der "Microsoft Excel Input" Step alle Dateien, die er mit den Wildcards findet.
Andere Beispiele für Wildcards:
(?i)daten.+\.xls
findet alle Dateien, die mit "Daten" bzw. "daten" beginnen und mit ".xls" enden.
Microsoft Excel Input Reiter Sheets
Dann wählen Sie das jew. Sheet aus, bzw. mehrere. Bei "Start row" und "Start column" beachten Sie bitte, dass Kettle bei 0 beginnt, nicht bei 1.
Microsoft Excel Input Reiter Content
Content / "Stop on empty row" kann ganz nütlich sein, hatten schon den Fall, dass plötzlich in Zeile 106.234 noch ein verwaister Wert stand, kostet viel Performance/Arbeitsspeicher
Microsoft Excel Input Reiter Fields
Bei Datentyp ggfs. TrimType "both" und für Ganzzahlen die zu Strings werden sollen Format # hilfreich
Ganz wichtige Erfahrungen:
Wenn Spaltenreihenfolge in ExcelDatei nicht mehr stimmt, merkt das Kettle anscheinend nicht an Bezeichnung in Header.
Arbeitet wohl "stupide" nach Reihenfolge, d.h. Spalte 1 soll im Kettle-Transformation den Namen "gebaeudenr" erhalten, wenn in der Exceldatei plötzlich "geschossnr" als Erstes kommt, merkt das System das nicht, spielt einfach falsch ein!!
Man kann bei Content Startspalte angeben, wenn man die Anfangsspalten nicht braucht. Spalte überspringen/aus LIste rauslöschen, funktionierte nicht, wenn man spätere Spalten noch brauchte, nur wenn man z.B. ab Spalte 6 gar nicht mehr braucht.
Wenn ein ClassCast Fehler kommt, muss man das logging auf ganz detailliert stellen, dann wird die Zeilennummer angezeigt.
-> Datumsfelder dürfen anscheinend nicht vor 1.1.1970 sein, Datum 1.1.1700 kam ClassCastException, 1.1.1999 nicht
Table Input
siehe unter Aus Excel in Datenbank schreiben / Eine Künstliche ID erzeugen
db/module/sva/etl/sap_hr/sap_load_stamm_laufbahn.kjb
Insert / Update Step
Kann verwendet werden, wenn man für bestehende Datensätze einen Update machen möchte und für noch nicht vorhandene Einträge einen Insert.
Aber auch, wenn man gar keine Updates machen will, sondern nur Inserts wenn noch kein Eintrag vorhanden ist.
siehe unter Aus Excel in Datenbank schreiben / Werte nachtragen (Beispiel erst Kosten- dann Beschäftigungsstellen)
Beispiel db/module/sva/etl/sap_hr/sap_load_stamm_beschstellen.ktr Step Insert sva_inst_neu
Stream Lookup
Wenn man Daten in Datenbanktabelle hat und ergänzen will um Input aus Exceldatei.
vergl. Stream Lookup
Problem kann keine komplexen where Bedingen wie < oder > machen
Database Join / Set Variable (eine Variable aus Datenbank lesen)
Database Join - Dieser Step kann benutzt werden, um eine Variable aus der Datenbank zu lesen und dem Flow hinzuzufügen.
Beispiel: select nvl(max(apnr::integer)+1,1) as laufbahn_max_apnr from sva_cifx where key=607;
Number of rows to return: 1
Dann "Set Variable Step" (Fieldname: laufbahn_max_apnr, Variable name: LAUFBAHN_MAX_APNR.
Vergl. sap_load_stamm_laufbahn.ktr
Da jedoch die einzelnen Transformationsschritte evtl. parallel laufen, muss man einen übergeordneten Job erstellen, der in der ersten Transformation zunächst die Variable liest und dann in der/den nächsten die Variable ausliest.
Vergl. sap_load_stamm_laufbahn.kjb und unten "eine künstliche ID erzeugen"
Get Variable
s.auch vorheriges Kapitel
Da jedoch die einzelnen Transformationsschritte evtl. parallel laufen, muss man einen übergeordneten Job erstellen, der in der ersten Transformation zunächst die Variable liest und dann in der/den nächsten die Variable ausliest.
Also in 1. Transformation "Set Variable Step"
Dann in der 2. Transformation z.B. Lesen aus Excel, "Get Variable" und wenn man es zum Schreiben braucht, "Join rows (cartesian product)".
Beispiel
Beispiel: sos/etl/gewichtung_fach_abschluss_fak/gewichtung_fach_abschluss_fak.kjb
Calculator (Werte berechnen, z.B. Multiplizieren)
Calculator Step, Funktion A*B, Field A "VAE" vorher Konstante c100 mit Wert 100 hinzugefügt als Wert B, um statt Prozentwert 0,27 eine 27 zu erhalten.
Beispiel sap_load_pfi
Text FIle Output (CSV-Dateien erzeugen)
relativ selbsterklärend.
Bei Zahlwerten kann Format 0.00 wichtig sein, damit amerikanisches und nicht deutsches Trennzeichen genutzt wird.
Bei Zahlen die Strings sind ggfs. auch Format # und Trim Type Both
Value Mapper (Werte transformieren)
Beispiel String "wiss. Dienst" -> 1 sonst 0 in sap_load_wiss_adt.ktr
String Cut
Hiermit kann man einen Ausschnitt von Strings ermitteln, Beispiel ersten zwei Stellen https://wiki.pentaho.com/display/EAI/Strings+cut
Execute SQL Script
SQL-Befehle ausführen.Erfahrung: direkt in Hauptjob sap_hr_sva.ktr nicht durchgelaufen (System hängt).
In einzelnen Job gepackt und Option "execute for each row" aktiviert, dann gings
sap_init_db.ktr
Generate Rows (Werte manuell erzeugen)
feste Schlüssel z.B. _unb für unbekannt manuell erzeugenBeispiel sap_load_stamm_bvl
Aus Exceldatei in Datenbank schreiben
Aus einem Sheet
Um Daten zu löschen legen man einen Step "Execute SQL script" an. Beispielhafter Inhalt delete from sva_pbl_neu;
Als Nächstes "Block until steps finishes"
- Dann "Microsoft Excel Input" -wichtig, Datentypen kontrollieren, S. unter Informationen zu einzelnen Steps / Microsoft Excel Input
Weiterhin war die Erfahrung, dass man bei Fields "Get Fields from Header row" Alle Felder drin lassen sollte, nicht nur die tatsächlich benötigten.
Andernfalls schien Kettle durcheinander zu kommen und meldete z.B. für Tarifart (String) falscher Datentyp (Date), weil er die falsche Spalte gelesen hat.
- Dann Table Output
Beispiel db/module/sva/etl/sap_hr/sap_load_pgd.ktr
Aus mehreren Sheets
Um aus mehreren Sheets zu lesen, muss man pro Sheet eine Transformation anlegen, da sonst im Flow die Felder aus dem ersten Sheet anscheinend nicht vom zweiten Sheet überschrieben werden.
Beispiel db/module/sva/etl/sap_hr/sap_load_pbl.ktr und sap_load_pbl2.ktr.
Die Informationen aus dem zweiten Sheet werden per "Update Step" nachgetragen.
Wenn in dem zweiten Excelsheet nicht definitiv alle primary keys enthalten sind, die im ersten sind, muss man "Skip Lookup" aktivieren, sonst kommt eine Fehlermeldung, dass z.B. für eine Personalnummer keine Amts-/Dienstbzeichnung gefunden wurden.
Entry to update with following key could not be found: 47
Max(Spalte) ermitteln und nachtragen
Im Beispiel soll das austrittsdatum aus einem Excelsheet nachgetragen werden, dazu muss man für jede Personalnummer das max(Ende) ermitteln.
Beispiel db/module/sva/etl/sap_hr/sap_load_pgd_austrittsdatum.ktr
Dies geht in dem man zunächst die Exceldatei einliest.
Dann ist für das "Group by" zunächst ein "Sort Rows" nötig.
Anschließend kommt ein "Group By"-Step
Und zum Schluss ein "Update"-Step - hier wieder "Skip lookup" aktivieren, siehe unter Aus Exceldatei in Datenbank schreiben / Aus mehreren Sheets
Calculator (Werte berechnen, z.B. Multiplizieren)
Calculator Step, Funktion A*B, Field A "VAE" vorher Konstante c100 mit Wert 100 hinzugefügt als Wert B, um statt Prozentwert 0,27 eine 27 zu erhalten.
Beispiel sap_load_pfi
Erst bestimme Zeilen rausfiltern und dann Update
Im Beispiel soll das Eintrittsdatum aus einem Excelsheet ermittelt werden, dazu muss man für jede Personalnummer nur die Zeilen mit DaArt=01 lesen und dann das min(Datum) bestimmen.
Beispiel db/module/sva/etl/sap_hr/sap_load_pgd_eintrittssdatum.ktr
Dies geht in dem man zunächst die Exceldatei einliest.
Dann folgt ein "Filter Rows" auf DatAr=01
Dann ist für das "Group by" zunächst ein "Sort Rows" nötig.
Anschließend kommt ein "Group By"-Step
Und zum Schluss ein "Update"-Step - hier wieder "Skip lookup" aktivieren, siehe unter Aus Exceldatei in Datenbank schreiben / Aus mehreren Sheets
Bei mehreren Datenzeilen Neuste raussuchen (Gültigkeit)
Im Beispiel soll zu Personalgrunddaten die aktuelleste Adresse PLZ etc ermittelt werden. Dazu gibt es ein Sheet, das pro Personalnummer mehrere Einträge mit Gültigkeiten (Beginn/Ende) geben kann.
Beispiel db/module/sva/etl/sap_hr/sap_load_pgd_wohnort.ktr
Vorgehen:
Excelsheet auslesen
Im Beispiel zusätzlich Filter auf Art=1 (ständiger Wohnsitz, nicht Zweitwohnsitz)
Sort Rows nach PersNr und Ende
Group By - Step mit Type "Last Value"
Dann wieder "Update Step"
Aus String Jahr "2000" ein Datum machen (1.1.2000)
Als erstes muss man einen FIlter machen mit der Einstellung nur Datensätze where is not null.
Dann "Add Constants" erster_erster 01/01/
Dann einen Concat step, bei der man die Felder erster_erster und das Zielfeld zusammenfügt.
Dann einen "Select Values" hier wählt man Felder aus, die im weiteren Flow berücksichtigt werden müssen und für das umzuwandelnde Feld, beim Reiter Metadata den Datentyp Date mit Format dd/MM/yyyy.
Beispiel db/module/sva/etl/sap_hr/sap_load_pgd_habil.ktr
Den kleineren/größeren Wert aus zwei Spalten ermitteln
Im Beispiel gibt es zwei Felder "Auf Zeit" und "Auf Lebenszeit", das Feld mit dem kleineren Wert in jeder Zeile soll genommen werden.
Dazu nutzt man einen "User Defined Java Expression" Step.
Damit Java die Variablen verarbeiten kann, zunächst einen "Select Values" Step und ändert die Feldnamen auf Namen ohne Leerzeichen, PersNr muss auch übergeben werden, da für Update benötigt.
Als Nächstes ein "User Defined Java Expression" mit der JavaExpression
(lebenszeit=null&&auf_zeit=null)?null:(lebenszeit=null&&auf_zeit!=null)?auf_zeit:(lebenszeit!=null&&auf_zeit=null)?lebenszeit:new Long(Math.min(lebenszeit,auf_zeit))
Also wenn beide Werte null sind, dann null, wenn einer der beiden null ist, dann den anderen und wenn beide gefüllt sind, dann das Minimum.
Wichtig ist, noch dass man bei dem langen Feld für Java Expression nicht übersieht, einen Datentyp auszuwählen.
Anschließend kann wie gewohnt, ein Update Step genutzt werden.
Beispiel db/module/sva/etl/sap_hr/sap_load_pgd_habil.ktr
Feld wird zu Decimalzahl 1020,0 transformiert soll aber String sein
Beim Einlesen von Kostenstellen kam es zu Problem, dass dass Feld zu einer Decimalzahl wie 1020,0 transformiert wurde, umstellen auf Datentyp Integer beim Einlesen oder entsprechender "Select Values" Step mit Meta-Datenänderung auf String brachte nichts.
1. Lösung: beim "Microsoft Excel Input Step" Reiter "Fields" geben Sie bei "Type" den Wert "String" und bei "Pattern" den Wert "#" an. Damit werden auch führende 0en beibehalten.
2. Lösung: ein "User Defined Java Step".
Die Java Expression Kostenst=null?null:Kostenst.trim().replaceAll(",0","") entfernte auch Leerzeichen am Anfang.
Beispiel db/module/sva/etl/sap_hr/sap_load_pfi.ktr
Eine Künstliche ID erzeugen
Für das Excelfeld "Laufbahngruppe" gibt es nur Bezeichnungstext, keinen Schlüssel.
Man kann so vorgehen:
FIlter Values - keine Nulls
Sort Values - by Laufbahngruppe
Unique Rows - Laufbahngruppe
Get Value from Sequence - Laufbahngruppe
In Datenbank schreiben.
Beispiel db/module/sva/etl/sap_hr/sap_load_stamm_laufbahn.ktr
Um diese ID dann bei der Verarbeitung der Rohdaten wieder auszulesen nutzt man "Database Lookup"
Beispiel db/module/sva/etl/sap_hr/sap_load_pbl.ktr.
Das ganze ist aber noch komplexer.
Nach dem ersten Durchlauf bzw. einiger Zeit existieren z.B. in sva_cifx (key=607) die Schlüssel 1-10 für verschd. Laufbahngruppen. Es könnte jedoch sein, dass irgendwann nicht mehr alle Daten übertragen werden, sondern z.B. nach Archivierung nur noch Personal ab 2019 oder so. In den Daten für 2019 ist vielleicht Laufbahnschlüssel 5 nicht mehr drin.
Darum sicherheitshalber folgendes Vorgehen.
Ein Job sap_load_stamm_laufbahn.kjb - erste Transformation liest max(apnr) aus der cifx und speichert in eine Variable (s. auch oben einzelne Schritte Table Input / Set Variable).
Zweite Transformation sap_load_stamm_laufbahn2.ktr liest die Laufbahngruppen aus Exceldatei , dann wird zusätzlich apnr_artifical hinzugefügt.
"Get Value from Sequence" - start at Value ${LAUFBAHN_MAX_APNR}
mit "Database Value Lookup" wird geprüft, ob es schon einen Eintrag in sva_cifx gibt, (wichtig: Do not pass row if lookup fails - darf nicht aktiviert sein).
Dann kann mit "Filter Rows" geprüft werden, ob schon eine Apnr in sva_cifx gefunden wurde, falls nein, neue mit der höheren Wert apnr_artifical in sva_cifx_neu einfügen,
falls ja trotzdem noch mal in sva_cifx_neu einspielen, damit die Bewegungsdaten einen vollständigen Lookup Database Value auf sva_cifx_neu machen können.
Hier ist auch Beispiel für Verzweigung True/False
sap_load_stamm_laufbahn2.ktr
Werte nachtragen (Beispiel erst Kosten- dann Beschäftigungsstellen)
Aufgabe: Zunächst sollen aus einem Sheet alle Kostenstellen eingetragen werden, dann bei den Beschäftigungsstellen diejenigen nachgetragen werden, die noch nicht als Kostenstellen eingetragen wurden.
Dazu kann man einen Insert / Update Step verwenden.
Es sollen keine Updates gemacht werden, die Maske ist zunächst etwas verwirrend. Man wählt "Don't perform any updates" aus.
Bei "Keys to look up" die key_apnr und das Feld im Stream (hier kostenstellenStr).
Dann steht da zwar "Update Fields", aber diese werden eingefügt, wenn noch kein Eintrag für die apnr in der Tabelle sva_inst_neu gefunden wurde.
Sicherheitshalber auch UPdate=N ausgewählt.
Beispiel db/module/sva/etl/sap_hr/sap_load_stamm_beschstellen.ktr Step Insert sva_inst_neu
"Zeitscheiben" ermitteln
Problem in sva_pbv_neu aus IT0016 gibt es eine Zeitscheibe
IT 0016 Personalnr 6333 01.08.2015- 31.07.2017
in IT0001 wird Mitarbeiterkreis und Dienstart nachgeschaut, dort gibt es aber zwei
6333 01.08.2015 31.10.2015 60
6333 01.11.2015 31.07.2017 60
--> keine Eindeutige zuordnung möglich mit einfachen it0016.Beginn<=it0001.Beginn and it0016.Ende>=it0001.Ende möglich
theoretisch wäre auch noch weitere Scheiben mit zwischenzeitlichen Makrs-Wechsel möglich
6333 1.8.2017 31.12.2018 50
6333 1.1.2019 31.12.2019 60
Lösung, Fehlfunktion von "Group by" nutzen, wenn man nicht ordentlich sortiert.
Es kommt immer der Hinweis
"The group by function needs the input to be sorted on the specific keys. If you don't sort in the input the results may not be correct".
Ergo: Sort by-Step nur nach Personalnr und Beginn
Dann "Group by" -> Group Fields PersNr, MAKrs und Aggregates "minBeginn Beginn Minimum" u. "maxEnde Ende Maximum".
Ergebnis Datenzeilen
Persnr minBeginn maxEnde Makrs
6333 1.8.2015 31.7.2017 60
6333 1.8.2017 31.12.2018 50
6333 1.1.2019 31.12.2019 60
Das wollen wir ja - hehe!!
vergl. db/module/sva/etl/sap_hr/sap_load_pbv_art_dienstart.ktr
Literaturtipps
- Pentaho Kettle Homepage: http://kettle.pentaho.com/
- Kettle FAQs: http://wiki.pentaho.com/display/EAI/Frequently+Asked+Questions
- Casters, M., Bouman,R., von Dongen, J. (2010). Pentaho Kettle Solutions. Building Open Source ETL Solutions with Pentaho Data Integration. Indianapolis, IN: Wiley.
- Haneke, U. et al. (2010). Open Source Business Intelligence. Möglichkeiten, Chancen und Risiken quelloffener BI-Lösungen. Wien: Hanser
- Roldan, M.C. (2013). Pentaho Data Integration Second Edition. Beginner's Guide. Birmingham, UK: Packt Publishing
- Javascript Guide des Mozilla Projektes: https://developer.mozilla.org/En/Core_JavaScript_1.5_Guide
- Javascript Anleitung im SelfHTML-Projekt: http://de.selfhtml.org/javascript/index.htm