Suchen...
Generic filters
Exact matches only
Search in title
Search in excerpt
Search in content

Für Präsentationszwecke: Daten kräftig durchmischen

Um bei Präsentationen das AS-Datenmodell eines Kunden zeigen zu können, muss zuerst einmal sichergestellt werden, dass nicht die echten Daten des Kunden zur Ansicht gebracht werden. Als wir vor solch einer Problemstellung standen, sind wir auf folgende Weise vorgegangen:

  1. Kopie der relationalen Datenbank (zumindest die T_DIM_* und die T_FACT_* Tabellen)
  2. Kopie der AS-Datenbank (Datenquelle anpassen)
  3. Verfremdung der Bezeichnungsfelder in den T_DIM_* Tabellen (wo notwendig)
  4. Verfremdung der Daten in den T_FACT_* Tabellen
  5. FullProcess der kopierten AS-Datenbank

Der letzte Punkt stellt eine besondere Herausforderung dar, da die Daten natürlich nicht mehr den Original-Daten entsprechen sollen – aber reine Fantasie-Daten machen auch keinen Sinn, weil dann jeglicher Bezug verloren geht. Sinnvoll ist es, die Daten innerhalb eines bestimmten Korridors zu ändern. Zum Beispiel in einem Bereich zwischen 75% und 110% des Originalwertes; oder vielleicht besser zwischen 70% und 85%?

Um diese Aufgabe zu lösen, haben wir eine einfache Stored-Procedure gebaut, mit der der Inhalt einer einzelnen Tabellenspalte in einem beliebigen Wertebereich geändert werden kann. Die Stored-Procedure ist fast ein Einzeiler:

UPDATE <TableName>
SET <Column> = Round((Max% ((Max% Min%) * RAND(<ColName>))) * <ColName>, 2)

Da in diesem einen Statement ziemlich viel passiert, möchten wir gerne den Inhalt Schritt für Schritt erklären:

  1. RAND(<ColName>): Die RAND()-Funktion erzeugt eine Zufallszahl zwischen 0 und 1. Wird die RAND()-Funktion ohne Parameter aufgerufen, dann wird für die Ausführung des Update-Statements nur eine einzige Zufallszahl erzeugt, die dann auf alle Wertberechnungen angewendet wird. Das würde bedeuten, dass alle Inhalte einer Spalte mit einem festen Faktor umgerechnet werden – so soll es ja gerade nicht sein. Aus diesem Grund wird hier beim Aufruf der RAND()-Funktion der Wert der Zelle als Parameter übergeben – dadurch bringt die RAND()-Funktion pro Zeile einen anderen Wert.
  2. Berechnung des “Zielwertfaktors”: Durch Angabe von Min% und Max% wird der Korridor vorgegeben, in dem sich der Wert in der Tabelle ändern soll. Jetzt muss nur noch eine Zufallszahl innerhalb dieses Bereiches ermittelt werden und mit dem Tabellenwert multipliziert werden. Hierfür wird zuerst die “Breite” des vorgegebenen Korridors ermittelt (Max% – Min%) und mit der Zufallszahl aus der RAND()-Funktion multipliziert. Da die RAND()-Funktion einen Wert zwischen 0 und 1 liegt, bekommen wir also immer ein Ergebnis, das kleiner oder gleich der Breite des Korridors ist. Wenn dieser Wert dann noch von Max% abgezogen wird, erhalten wir als Ergebnis immer eine Zahl im Bereich von [Min%;Max%]. Die vollständige Formel lautet:

(Max% – ((Max% – Min%) * RAND(<ColName>)))

  1. Berechnung des Zielwertes: Mit dem vorher berechneten Faktor kann jetzt der Wert aus der Tabelle multipliziert werden und heraus kommt ein verfremdeter Wert, der irgendwo im Bereich der vorgegebenen Abweichung vom Originalwert liegt.
  2. Rundung auf zwei Nachkommastellen: Mit der ROUND()-Funktion wird am Ende noch auf zwei Nachkommastellen gerundet.

Da das Anpassen dieses Update-Statements etwas umständlich ist, haben wir noch eine Stored-Procedure gebaut, die beim Aufrufen die notwendigen Parameter übergeben bekommt:

CREATE procedure [dbo].[sp_ReplaceValuesByRandom](
                    @TableName as nvarchar(50),
                    @ColName as nvarchar(50),
                    @MinPercentageOfValue as float,
                    @MaxPercentageOfValue as float,
                    @Decimals as int) as

BEGIN
    DECLARE @MinP as float, @MaxP as float
    SET @MinP = (@MaxPercentageOfValue - @MinPercentageOfValue) / 100
    SET @MaxP = @MaxPercentageOfValue / 100

    exec(N'
        UPDATE [' + @TableName + ']
        SET ' + @ColName + ' = Round((' + @MaxP + ' - ' +  @MinP + ' * Rand(' + @ColName + ')) * ' + @ColName + ', ' + @Decimals + ')')
END