LERNPFADE & KURSE

Subroutinen – Wiederverwendbarer Code für modulare Skripte

Autor

Qlik Doktor

Oktober 21, 2025 · 6 Min. Lesezeit

📚 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:

  1. Subroutinen mit SUB und END SUB erstellen und aufrufen (CALL).
  2. Parameter gezielt übergeben und Rückgabewerte mittels LET definieren.
  3. Eine zentrale Subroutine Library in einem Include-File aufbauen.
  4. 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?