📚 Qlik Sense Kurs – Artikel 23 von 28
← Vorheriger Artikel: Variablen & Include-Files
→ Nächster Artikel: Three-Stage Architecture
Was sind Subroutinen? Subroutinen sind definierte Code-Blöcke (Funktionen), die beliebig oft mit unterschiedlichen Parametern aufgerufen werden können. Sie sind der Schlüssel zur Wartbarkeit: Einmal schreiben, mehrfach verwenden, zentral warten!
Was lernst Du über Subroutinen – wiederverwendbaren Code für modulare Skripte?
Nach diesem Guide kannst Du:
- Subroutinen mit
SUBundEND SUBerstellen und aufrufen (CALL). - Parameter gezielt übergeben und Rückgabewerte mittels
LETdefinieren. - Eine zentrale Subroutine Library in einem Include-File aufbauen.
- Den Clean Code Ansatz der *Single Responsibility* auf Deine Ladeprozesse anwenden.
Zeitinvestment: 20 Min Lesen + 2 Std Hands-on
Quick Win: In 15 Minuten hast Du die erste generische Lade-Subroutine implementiert
Was ist das Prinzip DRY (Don’t Repeat Yourself) in Subroutinen?
Das Problem ohne Subroutinen: Jeder Load-Vorgang, jeder Quality Check und jeder Store-Befehl wird in Deinen Qlik-Scripts dupliziert. Bei einem notwendigen Bug-Fix (z.B. eine Anpassung im Error Handling) musst Du 20 oder mehr Stellen im Code manuell ändern – ein massives Fehlerrisiko!
Die Lösung mit Subroutinen: Definiere die Logik einmalig in einer zentralen Subroutine Library (typischerweise in einem Include-File). Eine Korrektur in dieser zentralen Bibliothek wirkt sofort in allen Apps, die sie verwenden.
Wie funktioniert die SUB…END SUB Syntax und der Aufruf (CALL)?
// Subroutine Definition
SUB SubroutineName(pParameter1, pParameter2)
// Der Code wird erst ausgeführt, wenn CALL aufgerufen wird
TRACE Processing: $(pParameter1) and $(pParameter2);
END SUB
// Subroutine Aufruf
CALL SubroutineName('Value_A', 'Value_B');
Erklärung der Schlüsselwörter:
- SUB: Leitet die Definition der Subroutine ein. Die Subroutine muss im Skript **vor** dem ersten Aufruf mit `CALL` definiert sein.
- Parameters: Werden in runden Klammern definiert (z.B. `pParameter1`). Es hat sich etabliert, das Präfix `p` (für Parameter) zu verwenden.
- END SUB: Beendet die Definition.
- CALL: Führt die Subroutine aus und übergibt die Werte der Argumente an die Parameter.
Was ist die Basic Subroutine – Generic Loader?
Eine der häufigsten Anwendungen ist das Erstellen eines generischen Loaders, der nur den Tabellennamen und den Pfad als Parameter benötigt.
SUB LoadTable(pTableName, pFilePath)
// Das Statement wird durch die Parameter dynamisch generiert
:
LOAD * FROM
(txt, codepage is 1252, embedded labels, delimiter is ',');
// Log Ergebnis mit variablen Namen
LET vRowCount = NoOfRows('$(pTableName)');
TRACE Loaded: $(pTableName) - $(vRowCount) rows;
END SUB
// Verwendung: Laden von 3 Tabellen mit minimalem Code-Aufwand
CALL LoadTable('Customers', 'lib://SourceData/');
CALL LoadTable('Products', 'lib://SourceData/');
CALL LoadTable('Orders', 'lib://SourceData/');
Vorteil: Wenn sich das Importformat (z.B. Delimiter) ändert, muss nur die `LoadTable`-Subroutine einmalig angepasst werden.
Wie definiert man Rückgabewerte mit LET?
Subroutinen haben keinen direkten `RETURN`-Befehl wie Funktionen in anderen Sprachen. Stattdessen werden Werte über einen **Output-Parameter** an das Hauptskript zurückgegeben, indem man eine Variable innerhalb der Subroutine mit `LET` setzt.
SUB CalculateSum(pField, pTable, vResultVariable)
// Berechne Summe und speichere das Ergebnis in der übergebenen Variablennamen
LET $(vResultVariable) = Sum($(pField), '$(pTable)');
TRACE Calculated sum of $(pField): $($(vResultVariable));
END SUB
// Verwendung: Der 3. Parameter (vTotalSales) ist der Name der Variable, die den Output erhält
CALL CalculateSum('Sales', 'SalesData', vTotalSales);
TRACE Gesamtumsatz: $(vTotalSales);
CALL CalculateSum('Quantity', 'SalesData', vTotalQty);
TRACE Gesamtmenge: $(vTotalQty);
Erklärung: Wir verwenden die Dollar-Sign Expansion doppelt: Zuerst wird der **Name** der Output-Variable (z.B. `vTotalSales`) übergeben. Innerhalb der Subroutine expandiert `$(vResultVariable)` zu `vTotalSales`, und `LET vTotalSales =…` speichert den berechneten Wert im globalen Skriptspeicher.
Wie funktioniert die Quality Check Subroutine in Subroutinen?
Subroutinen sind ideal, um wiederkehrende Validierungs- und Error-Handling-Aufgaben zu automatisieren. Dies baut direkt auf den Konzepten der Data Quality Gates auf.
SUB CheckQuality(pTable, pField, pThreshold, vIssueCount)
// Zähle NULL Values im Feld
LET vCount = Count(If(IsNull($(pField)), 1, 0), '$(pTable)');
// Speichere Ergebnis im Output-Parameter
LET $(vIssueCount) = $(vCount);
LET vTotalCount = NoOfRows('$(pTable)');
LET vNullPercent = Round($(vCount) / $(vTotalCount) * 100, 0.1);
// Warning bei Überschreitung des Thresholds
IF $(vNullPercent) > $(pThreshold) THEN
TRACE High NULL percentage in $(pTable).$(pField): $(vNullPercent)% > $(pThreshold)%;
END IF
END SUB
// Verwendung
CALL CheckQuality('Customers', 'Email', 5, vEmailNulls);
CALL CheckQuality('Orders', 'ShipDate', 1, vShipDateNulls);
TRACE Customer Email Issues: $(vEmailNulls) Records;
Vorteil: Die Logik ist zentralisiert, und das Hauptskript bleibt sauber und fokussiert auf den Datenfluss.
Wie funktioniert die Store & Drop Subroutine?
Komplexe Operationen wie das Speichern von QVDs und das anschließende Aufräumen von temporären Tabellen können in einer einzigen Subroutine gekapselt werden, inklusive einfacher Fehlerprüfung.
SUB StoreAndDrop(pTableName, pPath)
// Prüfe ob Tabelle existiert und nicht leer ist
LET vTableExists = NoOfRows('$(pTableName)') > 0;
IF $(vTableExists) THEN
// Store Logik (nutzt Pfad-Variable aus Include-File)
LET vStorePath = '$(vQVDPath)$(pTableName).qvd';
TRACE Storing: $(pTableName) to $(vStorePath);
STORE INTO (qvd);
// Aufräumen
DROP TABLE;
TRACE Dropped table: $(pTableName);
ELSE
TRACE Table $(pTableName) is empty or does not exist. Store skipped.;
END IF
END SUB
// Verwendung
CALL StoreAndDrop('STG_Customers', '');
CALL StoreAndDrop('TRF_Sales', '');
Was ist das Funktionsbibliotheksmuster und wie ist es organisiert?
Um die Vorteile von Subroutinen voll auszuschöpfen, lagern Sie diese in eine zentrale Bibliothek aus (typischerweise `03_Subroutines.qvs`), die Sie in all Ihren Apps über `$(Must_Include)` einbinden.
Der modulare Aufbau Deiner Skript-Struktur:
/QlikScripts/ |-- 01_Config.qvs // Globale Variablen & Pfade |-- 02_Functions.qvs // Utility-Funktionen (wie Datumskonverter) |-- 03_Subroutines.qvs // Alle SUB...END SUB Blöcke |-- MainApp.qvs // Ruft die Bibliotheken auf (CALL)
Die Subroutinen-Datei selbst sollte die Subroutinen klar nach ihrer Funktion gruppieren und mit einem klaren Naming-Prefix versehen:
| Prefix | Verwendungszweck | Beispiele |
|---|---|---|
Load |
Daten aus Quelle laden | LoadCSV, LoadQVD, LoadDatabase |
Store |
Daten speichern (QVD, Archive) | StoreTable, StoreArchive |
Check |
Validierung und Logging | CheckQuality, CheckFileExists, CheckDuplicates |
Log |
Protokollierung von Events | LogError, LogExecutionTime |
Was sind die besten Praktiken für Subroutinen in modularen Skripten?
✓ Design & Dokumentation:
- [ ] **Single Responsibility:** Jede Subroutine erledigt nur eine einzige Aufgabe (z.B. nur Laden, nicht Laden UND Speichern).
- [ ] Klare Naming Convention (Prefix-Tabelle).
- [ ] Parameter-Präfixe nutzen (`p` für Input, `v` für Output).
✓ Implementation:
- [ ] Temporäre Variablen am Ende der Subroutine aufräumen (`LET vVar = Null()`).
- [ ] Error Handling: Integriere `SET ErrorMode = 0` und `IF ScriptError <> 0` in kritische Load-Subroutinen.
✓ Organisation:
- [ ] Alle Subroutinen in einem zentralen Include-File (`03_Subroutines.qvs`) bündeln.
- [ ] Den Aufruf der Bibliothek im Hauptskript immer mit `$(Must_Include=…)` sichern.
Wie behebe ich Probleme mit Subroutinen in QlikView?
⚠️ Problem: Subroutine nicht gefunden (Unbekannte Operation: CALL)
Ursache: Die Definition (`SUB…END SUB`) muss im Skript **vor** dem ersten Aufruf (`CALL`) stehen. Wenn Sie eine Include-Datei verwenden, stellen Sie sicher, dass diese oben im Skript geladen wird.
// Richtig: Definition vor Aufruf
SUB MyFunction(pParam)
TRACE $(pParam);
END SUB
CALL MyFunction('test');
⚠️ Problem: Variable im Subroutine-Ergebnis fehlt (z.B. vTotalSales ist leer)
Ursache: Die Rückgabe-Variable wurde nicht korrekt mit der Dollar-Expansion in der `LET`-Anweisung gesetzt.
// Falsch: Speichert den Text "vTotalSales" als Literal-String
// LET vResultVariable = Sum(...)
// Richtig: Speichert den Wert in die Variable, deren NAME in vResultVariable steht
LET $(vResultVariable) = Sum($(pField), '$(pTable)');
Was sind die nächsten Schritte für Subroutinen in modularen Skripten?
Mit Subroutinen sind Sie bereit, die komplexen Ladeprozesse in wiederverwendbare Module aufzuteilen! Der nächste logische Schritt:
1. Three-Stage Architecture: Lerne, wie man Subroutinen nutzt, um die verschiedenen Layer (Staging, Transformation, Datenmodell) voneinander zu trennen und damit die Wartbarkeit und Skalierbarkeit massiv zu erhöhen. Lese dazu den nächsten Artikel: Three-Stage Architecture.
Welche verwandten Themen gibt es im Kurs zu Subroutinen für modulare Skripte?
- Variables & Includes – Notwendige Grundlage für Subroutinen-Libraries
- Three-Stage Architecture – Das Architektur-Konzept hinter Modularität
- Incremental Loading – Subroutinen sind ideal, um Delta-Loads zu automatisieren.