Ich arbeite mit einem Sternschema für ein Data Warehouse und habe ein Problem mit Kopf- und Werbebuchungen aus verschiedenen Datenquellen.
CREATE TABLE DataSourceAHeader
(
OrderId INT NOT NULL
,TotalCost MONEY NOT NULL
-- Date, etc...
);
CREATE TABLE DataSourceALine
(
OrderId INT NOT NULL
,LineNumber INT NOT NULL
-- Dates, etc...
);
CREATE TABLE DataSourceBLine
(
OrderId INT NOT NULL
,Cost MONEY NOT NULL
,LineNumber INT NOT NULL
);
Ich habe Datenquellen A und B, die dieselben Daten auf unterschiedliche Weise darstellen. Datenquelle A enthält Kopfzeilen und Werbebuchungen, enthält jedoch nur das Nettoergebnis (Gesamtkosten) in der Kopfzeile. Datenquelle B enthält nur Werbebuchungen und jede Position hat ein Ergebnis (Kosten).
Ich konnte zwei Faktentabellen halten (eine für den Kopf und eine für die Einzelposten), aber ich habe recherchiert und es scheint nicht ratsam. Gibt es eine Strategie, um mit dieser Art von nicht übereinstimmendem Format umzugehen, oder sollten sie in separaten Data Warehouses gespeichert werden (ein Warehouse pro Datenquelle)?
Meine aktuelle Strategie:
CREATE TABLE Fact.Order
(
Id BIGINT IDENTITY PRIMARY KEY
,OrderId INT NOT NULL
,Cost MONEY NOT NULL
-- Date key, etc...
);
CREATE TABLE Fact.OrderLine
(
Id BIGINT IDENTITY PRIMARY KEY
,OrderFactId BIGINT NOT NULL REFERENCES Fact.Order (Id)
,LineNumber INT NOT NULL
-- related line stuff
);
DataSourceAHeader
und DataSourceBLine
werden in Order
und eingefügt OrderLine
. DataSourceBLine
wird eine Zeile pro Zeile aufgeteilt.
Hier ist ein Beispiel für ein DataSourceAHeader
undDataSourceALine
SELECT * FROM Fact.Order;
|------------------------------------|
| Id | OrderId | Cost |
| 1 | 1100 | 12000.00 |
| 2 | 1101 | 10000.00 |
|------------------------------------|
SELECT * FROM Fact.OrderLine;
|-------------------------------------------|
| Id | OrderFactId | LineNumber |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
| 6 | 2 | 3 |
|-------------------------------------------|
Hier ist ein Beispiel für a DataSourceBLine
SELECT * FROM Fact.Order;
|---------------------------------|
| Id | OrderId | Cost |
| 1 | 1000 | 12.00 |
| 2 | 1000 | 10.00 |
|---------------------------------|
SELECT * FROM Fact.OrderLine;
|-------------------------------------------|
| Id | OrderFactId | LineNumber |
| 1 | 1 | 1 |
| 2 | 2 | 2 |
|-------------------------------------------|
Bearbeiten:
Das TotalCost
in der Kopfzeile kann nicht auf die Zeilenebene gebracht werden. Ich unterhielt mich mit einem Bekannten des Architekten und sein Rat war, zwei separate Faktentabellen zu implementieren, eine für die Kopfzeile (Zusammenfassung) und eine für die Zeilen (Detail), und nur NULL
Werte für die fehlenden Zeileninformationen für zu haben DataSourceA
.
Edit2:
Ich versuche, generisch mit der OrderId umzugehen, da ich mehrere weitere Datenquellen habe, die ähnliche OrderId-Schemata (Kollisionen) enthalten können. Ich habe eine Zuordnungstabelle implementiert, um die Quellkennungen in das Warehouse zu übersetzen.
Edit3:
Mit der Absicht, dass diese Frage nicht nur für mich selbst hilfreich ist, möchte ich, dass die Antwort die folgenden Details enthält (hauptsächlich, um zusammenzustellen, worüber alle bereits nachgedacht haben):
- Welche Ansätze gibt es im Allgemeinen, um verwandte disjunkte Datensätze in Form von Zusammenfassungen / Details (einzelne Faktentabelle oder Zusammenfassung / Detail-Faktentabellen) aufzulösen?
- Was sind die Nachteile jedes Ansatzes?
- Welche Struktur könnte die Faktentabelle annehmen, um mit fehlenden (oder irrelevanten) Daten umzugehen?
- (Zwei-Fakten-Tabellen-Ansatz) In welchen Fällen wäre es ratsam, die Zusammenfassung herunterzurollen, anstatt die Details aufzurollen?
quelle
DataSourceBLine
. Jede Werbebuchung wird zu einer separaten Zeile.Antworten:
Wenn Sie dies in eine einzelne Faktentabelle de-normalisieren möchten, handelt es sich in der Faktentabelle um Werbebuchungen. Daher müssen die Fakten von DataSourceAHeader aufgeteilt und an die entsprechenden Werbebuchungen verteilt werden, damit sie nicht dupliziert werden. Wie es derzeit dargestellt wird, bedeutet dies, dass Sie Ihre gesamten Bestellkosten senken und diese durch Summieren der Werbebuchungskosten berechnen.
Die DataSourceAHeader-Dimensionsschlüssel (z. B. Bestelldatum) können aus DataSourceAHeader entnommen und auf die aus DataSourceBLine generierten Faktenzeilen angewendet werden. Im Beispiel scheinen in DataSourceALine keine Informationen enthalten zu sein, die weder in DataSourceAHeader noch in DataSourceBLine bereits enthalten sind. Wenn dies jedoch der Fall ist, können diese auf ähnliche Weise zugeordnet werden.
Dieser Ansatz beruht auf einer Reihe von Annahmen. Die wichtigste ist, dass alle Fakten von DataSourceAHeader genau auf die einzelnen Werbebuchungen verteilt werden können. Wenn dies nicht der Fall ist, ist das Laden von zwei separaten Faktentabellen (eine für die Bestellung und eine für die Werbebuchungen) möglicherweise ein besserer Ansatz. Das Gleiche gilt möglicherweise, wenn viele Fragen zu Bestellungen gestellt werden müssen, bei denen keine Einzelposten-spezifischen Informationen berücksichtigt werden. Dies wird in dem Artikel, auf den Sie verwiesen haben, als "Bad Idea # 2" bezeichnet, aber ich habe festgestellt, dass es unter bestimmten Umständen tatsächlich eine gute Idee ist.
Schließlich wird davon ausgegangen, dass die beiden Datenquellen synchron sind. Wenn dies nicht der Fall ist, beschränken Sie sich darauf, Daten im Tempo der langsameren Datenquelle zu laden. Dies mag in Ordnung sein, muss jedoch im Kontext Ihrer Anforderungen und des Unterschieds zwischen den beiden Datenquellen berücksichtigt werden.
Bearbeiten: Die De-Normalisierung in eine einzelne Faktentabelle kann die Leistung beim Zählen von Aufträgen erheblich beeinträchtigen, da es sich im Wesentlichen um eine eindeutige Zählung handelt. Dies wäre mein Hauptgrund für die Berücksichtigung von zwei separaten Faktentabellen.
Bearbeiten 2 (als Antwort auf die Frage bearbeiten):
Hier besteht das Problem darin, dass auf der detailliertesten Ebene (Linien-) Daten unvollständig sind, da nicht alle Zeilen einen Kostenwert haben. Die Gesamtkosteninformationen sind jedoch auf der nächsthöheren Ebene (Kopfzeile) verfügbar. Dies stellt die Situation dar, in der Sie die höhere Ebene nicht von der niedrigeren ableiten können. Betrachten wir die resultierenden Optionen:
Diese Frage wurde aufgrund von Zweifeln an zwei verwandten Faktentabellen aufgeworfen. Die Zweifel ergeben sich aus der Tatsache, dass das Verwalten und Verbinden von zwei großen Faktentabellen ressourcenintensiv sein kann. Das stimmt, und wenn Ihre detailliertesten Informationen verwendet werden können, um eine vollständige Beschreibung der Situation bereitzustellen, ist die Verwendung einer einzelnen Faktentabelle vorzuziehen. In solchen Situationen, in denen dies nicht möglich ist, sind jedoch zwei Faktentabellen erforderlich, wenn Sie so viele Informationen wie möglich aufbewahren möchten.
quelle
all the facts from DataSourceAHeader can accurately be distributed among its constituent line items
DasDataSourceAHeader
kann nicht auf die Zeilen verteilt werden, daher denke ich, dass zwei separate Tabellen benötigt werden. Siehe meine Bearbeitung der Frage unten.Beginnen wir mit der Annahme, dass Sie nur eine Faktentabelle für "Bestellungen" benötigen. Dieser Ansatz ist in 99% der Fälle korrekt und Ihr Szenario ist ziemlich normal.
Deklarieren Sie den Gewinn der Faktentabelle: Eine Zeile pro Bestellposition.
Bestimmen Sie die Dimensionsattribute (Bestelldatum, Versanddatum, Kunde, Produkt usw.). Diese sind eine Mischung aus Bestellkopf und Bestellposition. Die Bestellnummer (Order.OrderId?) Wird zu einer "entarteten Dimension" (Sie haben keine Dimension "Bestellungen", da alle interessanten Attribute bereits entfernt wurden und nur die Bestellnummer übrig bleibt.)
Bestimmen Sie die Fakten. Dies sind die mit der Bestellung verbundenen Messungen. Menge, Kosten, Umsatz usw. Sie möchten dann additiv bleiben, also Menge und erweiterten Preis speichern, nicht Preis pro Stück. Messungen, die nur auf Kopfebene existieren, müssen der Zeilenebene zugeordnet werden.
Wenn das Unternehmen zögert, die Kosten auf Auftragsebene der Werbebuchung zuzuordnen, ist das schade. Sie erhalten ein besseres Data Warehouse, wenn sie dies tun.
quelle
TotalCost
in der Kopfzeile kann nicht auf die Zeilenebene gebracht werden. Ich unterhielt mich mit einem Bekannten des Architekten und sein Rat war, zwei separate Faktentabellen zu implementieren, eine für die Kopfzeile (Zusammenfassung) und eine für die Zeilen (Detail), und nurNULL
Werte für die fehlenden Zeileninformationen fürDataSourceA
(ZeileCost
) zu haben.DataSourceA
es keine Leitungskosten (nur Leitungsinformationen) oder eine Methode zum Ableiten der Leitungskosten gibt. Ich erhalte diese Daten wie sie sind und kann den Anbieter leider nicht zwingen, sein System zu ändern.Versuchen Sie, sich von beliebigen Primärschlüsseln zu entfernen. Bei Bestellungen gibt es einen nützlichen Schlüssel in der Bestellnummer. Die Zeilennummern sind auch in Kombination mit der Bestellnummer eindeutig. Beim Laden der Daten sollten Ausnahmen wie Duplikate abgefangen werden.
Alle Ihre primären und ausländischen Einschränkungen für die von Ihnen freigegebenen Daten müssen auf der Bestellnummer und der Zeilennummer basieren, wobei die Mitte des Sterns den Auftragskopf und die Gesamtkosten sowie die Werbebuchungen in einer separaten Tabelle mit den zugehörigen Kosten und anderen Daten enthält aus beiden Quellen in diskreten Spalten
quelle
OrderId
da ich mehrere weitere Datenquellen habe, die ähnlicheOrderId
Schemata (Kollisionen) enthalten können. Ich habe eine Zuordnungstabelle implementiert, um die Quellkennungen in das Warehouse zu übersetzen.