LERNPFADE & KURSE

Slowly Changing Dimensions Type 2 in Qlik implementieren

Autor

Qlik Doktor

Oktober 6, 2025 · 9 Min. Lesezeit

📚 Qlik Sense Kurs – Artikel 13 von 28

Vorheriger Artikel: Link Tables für Many-to-Many-Beziehungen
Nächster Artikel: Temporale Daten & IntervalMatch

Was ist SCD Type 2? Eine Methode zur Historisierung von Dimensionsänderungen. Wenn ein Kunde die Region wechselt, wird die alte Version behalten und eine neue erstellt – so bleiben historische Analysen korrekt!

Was wirst Du über Slowly Changing Dimensions Type 2 in Qlik lernen?

Nach diesem Guide kannst Du:

  1. SCD Type 2 Dimensionen in Qlik implementieren
  2. Point-in-Time-Analysen durchführen (Sales mit der Region verknüpfen die zum Verkaufszeitpunkt aktuell war)
  3. Historische Änderungen tracken und auswerten

Zeitinvestition: 30 Min Lesen + 4 Std Hands-on
Voraussetzung: Kenntnisse in Fact vs Dimension Design
Quick Win: In 20 Minuten verstehst Du das Konzept und kannst erste SCD2-Dimensionen erstellen

Wie ändert man Dimensionen bei Slowly Changing Dimensions Type 2 in Qlik?

Das Problem: Dein Kunde «Müller AG» war 2020-2022 in der Region «Nord». Ab Juli 2022 ist er in Region «Süd». Wenn Du jetzt Sales aus 2021 analysierst – welche Region soll angezeigt werden? Die aktuelle (Süd, falsch!) oder die damalige (Nord, richtig!)?

Ohne SCD2 (Standard):

Customer:
CustomerID | Name      | Region
CUST001    | Müller AG | Süd      ← Aktuell, überschreibt alte Region

Sales 2021 → Region "Süd" (FALSCH! War damals "Nord")

Die Lösung: SCD Type 2 Erstelle eine neue Version des Records, behalte die alte. So kannst Du historische Sales der richtigen (damaligen!) Region zuordnen.

Mit SCD2:

Customer_SCD2:
SurrogateKey | CustomerID | Name      | Region | StartDate  | EndDate    | IsCurrent
1            | CUST001    | Müller AG | Nord   | 2020-01-01 | 2022-06-30 | 0
2            | CUST001    | Müller AG | Süd    | 2022-07-01 | NULL       | 1

Sales 2021 → SurrogateKey 1 → Region "Nord" (RICHTIG!)
Sales 2023 → SurrogateKey 2 → Region "Süd" (RICHTIG!)

Wie versteht man die Struktur von SCD Type 2?

Eine SCD2-Dimension hat diese Pflichtfelder:

Was ist ein Surrogate Key (Technischer Schlüssel) in Qlik?

CustomerSurrogateKey: 1, 2, 3, 4, ...

Erklärung: Eindeutiger Key pro VERSION. Auto-Increment. Dieser Key wird in Fact-Tabellen referenziert!

Wie implementiere ich den Business Key in Slowly Changing Dimensions Type 2 in Qlik?

CustomerID: CUST001, CUST001, CUST002, ...

Erklärung: Die «echte» Customer-ID aus dem Quellsystem. Bleibt gleich über alle Versionen.

Was sind Attribute, die sich ändern können, in Slowly Changing Dimensions Type 2?

CustomerName, Region, Segment, ...

Erklärung: Die Felder die sich ändern können und historisiert werden sollen.

Was sind die Effective Dates in Slowly Changing Dimensions Type 2 in Qlik?

EffectiveStartDate: 2022-07-01
EffectiveEndDate: NULL (= noch aktuell) oder 2023-12-31 (= wurde abgelöst)

Erklärung: Wann war diese Version gültig? NULL bei EndDate bedeutet: Ist aktuell noch gültig.

Was ist das IsCurrent Flag bei Slowly Changing Dimensions Type 2 in Qlik?

IsCurrent: 1 = aktuell, 0 = historisch

Erklärung: Schneller Zugriff auf die aktuelle Version ohne Datumsvergleich.

Wichtig: Facts müssen den Surrogate Key referenzieren, nicht den Business Key! Nur so funktioniert Point-in-Time richtig.

Wie erstelle ich SCD2: Initial Load in Qlik?

Beim ersten Mal lädst Du alle Kunden als Version 1:

// Quelle laden
Temp_Customers:
LOAD
    CustomerID,
    CustomerName,
    Region,
    Segment,
    Date(ModifiedDate) as SourceModifiedDate
FROM [DataCustomers.xlsx]
(ooxml, embedded labels);

Erklärung: Standard-Load der Quelldaten. ModifiedDate ist das Datum der letzten Änderung im Quellsystem.

// SCD2 Struktur aufbauen
Dim_Customer_SCD2:
LOAD
    RowNo() as CustomerSurrogateKey,              // 1, 2, 3, ...
    CustomerID,                                    // Business Key
    CustomerName,
    Region,
    Segment,
    Date(SourceModifiedDate) as EffectiveStartDate,
    Date(Null()) as EffectiveEndDate,             // NULL = aktuell
    1 as IsCurrent,                               // Alle initial current
    1 as VersionNumber,                           // Erste Version
    Hash128(CustomerName, Region, Segment) as AttributeHash  // Für später
RESIDENT Temp_Customers;

Erklärung der Felder:

  • RowNo(): Erstellt automatisch 1, 2, 3, … als Surrogate Key
  • EffectiveEndDate = Null(): Noch keine Vorgänger-Version, also alle aktuell
  • IsCurrent = 1: Alle sind initial die aktuelle Version
  • AttributeHash: Kombiniert alle Attribute in einen Hash – später für Change Detection!
DROP TABLE Temp_Customers;

// SCD2 speichern
STORE Dim_Customer_SCD2 INTO [QVDDim_Customer_SCD2.qvd] (qvd);

Erklärung: Die SCD2-Dimension wird als QVD gespeichert, beim nächsten Reload wird sie inkrementell aktualisiert.

Wie aktualisiert man SCD2 mit einem Incremental Update in Qlik?

Beim nächsten Reload erkennst Du Änderungen und erstellst neue Versionen:

Wie lade ich alte SCD2 und neue Source in Qlik?

// 1. Alte SCD2 Dimension laden
Dim_Customer_SCD2_Old:
LOAD * FROM [QVDDim_Customer_SCD2.qvd] (qvd);

// 2. Neue Source Daten laden
Temp_Customers_New:
LOAD
    CustomerID,
    CustomerName,
    Region,
    Segment,
    Date(ModifiedDate) as SourceModifiedDate,
    Hash128(CustomerName, Region, Segment) as AttributeHash  // Gleicher Hash!
FROM [DataCustomers.xlsx]
(ooxml, embedded labels);

Erklärung: Wir laden sowohl die alte SCD2 als auch die neuen Source-Daten. Der Hash wird wieder berechnet – gleiche Formel wie beim Initial Load!

Wie identifiziere ich Änderungen mit Hash-Vergleich in Qlik?

// 3. Changes finden durch Hash-Vergleich
Temp_Changes:
LOAD
    n.CustomerID,
    n.CustomerName,
    n.Region,
    n.Segment,
    n.SourceModifiedDate,
    n.AttributeHash as NewHash,
    o.AttributeHash as OldHash,
    o.CustomerSurrogateKey as OldSurrogateKey,
    o.VersionNumber as OldVersionNumber
FROM Temp_Customers_New n
LEFT JOIN (Dim_Customer_SCD2_Old o)
ON n.CustomerID = o.CustomerID
WHERE o.IsCurrent = 1;                  // Nur aktuelle Versionen vergleichen

Erklärung: Wir joinen neue Daten (n) mit alten Daten (o) über CustomerID. Aber nur die aktuellen Versionen (IsCurrent = 1) interessieren uns!

// 4. Nur wirklich geänderte Records
Temp_Changed:
LOAD *
RESIDENT Temp_Changes
WHERE NewHash <> OldHash         // Hash unterschiedlich = Änderung!
   OR IsNull(OldHash);           // Oder neuer Kunde (noch kein Hash)

Erklärung: Der Trick: Wenn NewHash ≠ OldHash, hat sich mindestens ein Attribut geändert. Wenn OldHash NULL ist, ist es ein neuer Kunde.

Performance-Tipp: Hash-Vergleich ist 2.4x schneller als Feld-für-Feld-Vergleich (5 Sek vs 12 Sek bei 50k Records)!

Wie schließt man alte Versionen in Schritt 3 in Qlik?

// 5. Alte Versionen schließen (EndDate setzen, IsCurrent = 0)
Dim_Customer_SCD2_Updated:
LOAD
    CustomerSurrogateKey,
    CustomerID,
    CustomerName,
    Region,
    Segment,
    EffectiveStartDate,
    Date(Today()-1) as EffectiveEndDate,    // Gestern geschlossen
    0 as IsCurrent,                         // Nicht mehr current
    VersionNumber,
    AttributeHash
RESIDENT Dim_Customer_SCD2_Old
WHERE EXISTS(CustomerID, CustomerID)        // Nur für geänderte Kunden
  AND IsCurrent = 1;                        // Die aktuell noch current sind

Erklärung: Für alle geänderten Kunden setzen wir die alte Version auf IsCurrent=0 und EffectiveEndDate=Gestern. So ist sie historisch, aber nicht gelöscht!

Wie füge ich neue Versionen in Slowly Changing Dimensions Type 2 in Qlik hinzu?

// 6. Neue Versionen erstellen
LET vMaxSurrogateKey = Peek('CustomerSurrogateKey', -1, 'Dim_Customer_SCD2_Updated');

CONCATENATE(Dim_Customer_SCD2_Updated)
LOAD
    $(vMaxSurrogateKey) + RowNo() as CustomerSurrogateKey,  // Neue Keys!
    CustomerID,
    CustomerName,
    Region,
    Segment,
    Date(Today()) as EffectiveStartDate,
    Date(Null()) as EffectiveEndDate,
    1 as IsCurrent,
    OldVersionNumber + 1 as VersionNumber,      // Version + 1
    NewHash as AttributeHash
RESIDENT Temp_Changed
WHERE NOT IsNull(OldHash);                      // Nur Changes, keine neuen

Erklärung der Details:

  • Peek(‚CustomerSurrogateKey‘, -1, …): Holt den höchsten existierenden Surrogate Key
  • $(vMaxSurrogateKey) + RowNo(): Neue Keys starten nach dem höchsten alten
  • OldVersionNumber + 1: Version hochzählen (1 → 2 → 3 …)

Ergebnis: Du hast jetzt sowohl die alte Version (geschlossen) als auch die neue Version (current) in der Dimension!

Wie verbindet man Facts mit SCD2 für Point-in-Time Lookup?

Der kritische Teil: Facts müssen zum richtigen Zeitpunkt den richtigen Surrogate Key bekommen!

// Facts laden
Temp_Sales:
LOAD
    OrderID,
    CustomerID,
    ProductID,
    Date(OrderDate) as OrderDate,
    Amount,
    Quantity
FROM [DataSales.xlsx]
(ooxml, embedded labels);
// SCD2 Dimension laden
Dim_Customer_SCD2:
LOAD
    CustomerSurrogateKey,
    CustomerID,
    CustomerName,
    Region,
    EffectiveStartDate,
    EffectiveEndDate
FROM [QVDDim_Customer_SCD2.qvd] (qvd);
// Point-in-Time Join
Facts_Sales:
LOAD
    OrderID,
    CustomerID,
    ProductID,
    OrderDate,
    Amount,
    Quantity
RESIDENT Temp_Sales;

LEFT JOIN (Facts_Sales)
LOAD
    CustomerID,
    CustomerSurrogateKey,
    EffectiveStartDate,
    EffectiveEndDate
RESIDENT Dim_Customer_SCD2;

Erklärung: Der LEFT JOIN verbindet Sales mit ALLEN Versionen des Kunden. Jetzt haben wir temporär zu viele Zeilen!

// Final: Nur die richtige Version behalten
Facts_Sales_Final:
LOAD
    OrderID,
    CustomerSurrogateKey,      // Statt CustomerID!
    ProductID,
    OrderDate,
    Amount,
    Quantity
RESIDENT Facts_Sales
WHERE OrderDate >= EffectiveStartDate
  AND (IsNull(EffectiveEndDate) OR OrderDate <= EffectiveEndDate);

Erklärung des WHERE:

  • OrderDate >= EffectiveStartDate: Sale ist nach Start der Version
  • IsNull(EffectiveEndDate): Version ist noch aktuell (keine EndDate) ODER
  • OrderDate <= EffectiveEndDate: Sale ist vor Ende der Version

Das Ergebnis: Jede Sale hat jetzt den CustomerSurrogateKey der Version die zum OrderDate gültig war. Point-in-Time perfect!

Wie kann ich IntervalMatch für Point-in-Time in Qlik verwenden?

Eine elegantere Methode für große Dimensionen ist IntervalMatch:

// Facts laden
Facts_Sales:
LOAD
    OrderID,
    CustomerID,
    ProductID,
    Date(OrderDate) as OrderDate,
    Amount
FROM [DataSales.xlsx]
(ooxml, embedded labels);
// SCD2 Dimension
Dim_Customer_SCD2:
LOAD
    CustomerSurrogateKey,
    CustomerID,
    CustomerName,
    Region,
    EffectiveStartDate,
    EffectiveEndDate
FROM [QVDDim_Customer_SCD2.qvd] (qvd);
// IntervalMatch: OrderDate in Gültigkeitszeitraum
Temp_Interval:
IntervalMatch(OrderDate, CustomerID)
LOAD DISTINCT
    EffectiveStartDate,
    If(IsNull(EffectiveEndDate), Date(Today()+1000), EffectiveEndDate) as EffectiveEndDate,
    CustomerID
RESIDENT Dim_Customer_SCD2;

Erklärung von IntervalMatch:

  • Sucht für jede OrderDate+CustomerID die passende Zeitspanne
  • If(IsNull(EffectiveEndDate), …) ersetzt NULL durch ein weit in der Zukunft liegendes Datum
  • IntervalMatch erstellt automatisch die Verknüpfung!
// Join für Surrogate Key
LEFT JOIN (Facts_Sales)
LOAD
    CustomerID,
    CustomerSurrogateKey,
    EffectiveStartDate,
    EffectiveEndDate
RESIDENT Dim_Customer_SCD2;

Erklärung: Jetzt können wir den Surrogate Key holen. IntervalMatch hat bereits die richtige Version gefunden!

Vorteil IntervalMatch: Kompakter Code, bei großen Dimensionen performanter. Mehr dazu in Temporale Daten & IntervalMatch.

Wie kann man typische Fehler bei Slowly Changing Dimensions Type 2 in Qlik vermeiden?

⚠️ Fehler 1: Facts verwenden Business Key statt Surrogate Key

Symptom: Historische Analysen zeigen immer aktuelle Attribute.

Falsch:

Facts_Sales:
- OrderID
- CustomerID              // Business Key - immer alle Versionen verknüpft!
- Amount

Richtig:

Facts_Sales:
- OrderID
- CustomerSurrogateKey    // Surrogate Key - Point-in-Time korrekt!
- Amount

Warum wichtig: CustomerID verbindet sich mit ALLEN Versionen. Qlik weiß nicht welche die richtige ist. CustomerSurrogateKey ist eindeutig für eine Version!

⚠️ Fehler 2: Mehrere Records mit IsCurrent = 1

Symptom: Ein Kunde hat mehrere «aktuelle» Versionen.

Ursache: Beim Update wurde die alte Version nicht auf IsCurrent=0 gesetzt.

Diagnose:

// Check: Wie viele Current pro Customer?
CheckCurrent:
LOAD
    CustomerID,
    Count(*) as CurrentCount
RESIDENT Dim_Customer_SCD2
WHERE IsCurrent = 1
GROUP BY CustomerID
HAVING Count(*) > 1;

Lösung: Stelle sicher dass beim Schließen alter Versionen IsCurrent explizit auf 0 gesetzt wird (siehe Code oben).

⚠️ Fehler 3: Duplicate Surrogate Keys

Symptom: Surrogate Key ist nicht eindeutig, Joins funktionieren nicht.

Falsch:

// FALSCH: RowNo() startet bei jedem LOAD bei 1!
CustomerSurrogateKey = RowNo()

Richtig:

// RICHTIG: Höchsten existierenden Key finden, dann weiterzählen
LET vMaxSurrogateKey = Peek('CustomerSurrogateKey', -1, 'OldDimension');
CustomerSurrogateKey = $(vMaxSurrogateKey) + RowNo()

Warum wichtig: Surrogate Keys müssen ÜBER ALLE LOADS eindeutig bleiben, nicht nur innerhalb eines Loads!

Wie erstelle ich eine Best Practices Checklist für Slowly Changing Dimensions Type 2 in Qlik?

✓ Struktur:

  • [ ] Surrogate Key (Auto-Increment, eindeutig)
  • [ ] Business Key (CustomerID, bleibt über Versionen gleich)
  • [ ] EffectiveStartDate & EffectiveEndDate (Gültigkeitszeitraum)
  • [ ] IsCurrent Flag (1=aktuell, 0=historisch)
  • [ ] Optional: VersionNumber (für Debugging)

✓ Change Detection:

  • [ ] Hash128() für alle zu trackenden Attribute verwenden
  • [ ] Hash-Vergleich statt Feld-für-Feld (2.4x schneller)

✓ Facts Integration:

  • [ ] Facts referenzieren Surrogate Key, NICHT Business Key
  • [ ] Point-in-Time Lookup mit WHERE oder IntervalMatch

✓ Performance:

  • [ ] Separate Current-Tabelle für schnelle Standard-Analysen
  • [ ] QVD-Architektur (Staging → Transform → Model)

Wie implementiert man Slowly Changing Dimensions Type 2 in Qlik für Sales-Analyse mit Region-Wechsel?

Szenario: Kunde «Müller AG» wechselt am 01.07.2022 von Region Nord nach Süd.

SCD2 Dimension:
SurrogateKey | CustomerID | Name      | Region | StartDate  | EndDate    | IsCurrent
1            | CUST001    | Müller AG | Nord   | 2020-01-01 | 2022-06-30 | 0
2            | CUST001    | Müller AG | Süd    | 2022-07-01 | NULL       | 1

Facts:
OrderID | CustomerSurrogateKey | OrderDate  | Amount
ORD001  | 1                    | 2021-05-15 | 5000€   ← Version 1 (Nord)
ORD002  | 2                    | 2023-03-10 | 8000€   ← Version 2 (Süd)

Analyse: Sum(Amount) by Region

  • Nord: 5000€ (ORD001 mit Surrogate Key 1)
  • Süd: 8000€ (ORD002 mit Surrogate Key 2)

Perfekt! Historische Sales werden der Region zugeordnet die zum Verkaufszeitpunkt gültig war. So sind Trend-Analysen korrekt!

Was sind die nächsten Schritte zur Implementierung von Slowly Changing Dimensions Type 2 in Qlik?

Du kannst jetzt SCD Type 2 Dimensionen implementieren! Als nächstes:

1. IntervalMatch vertiefen: SCD2 nutzt oft IntervalMatch für Point-in-Time. Temporale Daten & IntervalMatch zeigt Dir alle Details und weitere Use Cases.

2. Incremental Loading: SCD2 Updates sind Teil einer größeren Incremental Loading Strategie. Incremental Loading Patterns zeigt das große Bild.

3. IterNo für iterative Updates: Komplexere SCD2-Updates können mit LOAD WHILE optimiert werden. IterNo & WHILE Patterns erklärt wie.

Welche verwandten Themen gibt es im Kurs zu Slowly Changing Dimensions Type 2 in Qlik?

Slug: qlik-scd-implementation
Keywords: Qlik SCD Type 2, Slowly Changing Dimensions Qlik, Historisierung Qlik, Point-in-Time Qlik, Surrogate Keys Qlik, SCD2 Implementation, IntervalMatch SCD, Qlik Dimension Versioning, Effective Dates Qlik, Qlik Change Detection