2016-07-29 14 views
1

Ich habe 4 Tabellen mit Daten, denen ich zu einer Tabelle Termintabelle beitreten möchte, aber es wird zurückgegeben viele Duplikate mit linken Joins.Ich habe 3 Tabellen mit Datumsangaben, denen ich mit einer Datumsdimensionstabelle beitreten möchte, aber es gibt viele Duplikate mit linken Verknüpfungen zurück

Tabellen sind im Grunde ein Datumsfeld, das ich zählen möchte.

Dies sind eigentlich eine Tabelle mit den separaten Daten, die ich 3 mal an die Dimensionstabelle anschließe, um einen Datensatz zu erhalten. Auch diese Tabelle

compdate datetime, fteam varchar(20) 

und das Datum Dimensionstabelle als Datum in yyyymmdd, die ich auf dem Datumsfeld verbinden. als

select cp.fteam,md.mdate,sd.sdate,bd.bdate,cp.cpdate,d.date 

    into #resultstable 

    from datedimension d 
    left join mdate md 
    on d.date = convert(date,md.mdate,103) 
    left join sentdate sd 
    on d.date = convert(date,sd.sdate,103) 
    left join bacdate bd 
    on d.date = convert(date,bd.bdate,103) 
    left join compdate cp 
    on d.date = convert(date,cp.cdate,103) 

dies tun mag ich die Daten in der Datumsdimension mir ein Datum geben, die ich auf eine where-Klausel verwenden kann, für einen Bericht zählt jedes Datum aus den 4 verschiedenen Tabellen zu erhalten.

Allerdings gibt es mir viele Wiederholungen, da jedes Mal, wenn es ein übereinstimmendes Datum gibt, die gleiche Zeile wiederholt für das übereinstimmende Datum auf allen Tabellen wiederholt wird. Dies gibt viele Zählungen, die falsch sind. dh wenn MD-Tabelle hat einen Datensatz 2 Datensätze für 2016/06/29 und CP hat 3 und BD hat sechs Das Dimensionsdatum Ergebnis wird 36 sein! für md wenn es nur 2 anzeigen soll, also 6x3x2.

Wie kann ich diese Tabellen mit Wiederholungen und falschen Ergebnissen verbinden.

Ich dachte, es wäre eine Standardmethode, um Faktentabellen mit einer Dimensionstabelle zu verbinden, um genaue Ergebnisse zu erhalten und nicht Duplikate, da Sie Joinsätze zusammenfügen.

Ich habe versucht, nur die Daten von jeder Tabelle nur zu wählen, aber es gibt immer noch Wiederholungen. Ich kann kein Schema als Firmendetails anzeigen, aber Sie können ein hypothetisches aus den Tabellen zusammenstellen.

+0

Nicht verwandt mit Ihrer Frage, aber warum speichern Sie Datumsangaben als Zeichenfolgen in Ihrer Dimensionstabelle? –

+0

Datumsangaben sind Datumsangaben, keine Zeichenketten, die Konvertierung soll den Zeitteil entfernen. –

+0

Ich denke, dass Ihre mehreren Faktentabellen kollidieren. Wenn Sie sich vorstellen können, dass der Mocdate-Tisch nur zwei Zeilen enthält, die beide das Datum 01.01.2016 haben. Wenn Sie nur die Datendimension zu mocdate hinzufügen, erhalten Sie 2 Datenzeilen zurück. Nun stellen Sie sich vor, senddate hat nur eine Zeile Daten, auch für 1/1/2016. Wenn Sie jetzt senddate der oben erstellten virtuellen Tabelle beitreten, erhalten Sie 2 Zeilen von senddate, da es aufgrund von mocdate bereits 2 Zeilen gibt. – Bostaevski

Antwort

0

Sie sollten eine einzelne Datumstabelle, der Sie beitreten, aus der Faktentabelle mehrere Male haben. Dies wird als Rollenspieldimension bezeichnet. Ihre Anfrage wird wie folgt aussehen:

SELECT fact.* 
,COALESCE(moc.datekey, @unknownDateKey) 
,COALESCE(sent.datekey, @unknownDateKey) 
FROM factTable fact 
LEFT OUTER JOIN date moc 
ON fact.mocdate = moc.date 
LEFT OUTER JOIN date sent 
ON fact.sentdate = sent.date 

Sie die @unknownDateKey haben würde als eine Variable über die für die Dimension der Schlüssel des unbekannten Mitglied eingestellt ist.

+0

Das ist, was ich versuche, mit der Datumsdimensionstabelle zu tun, ich schließe die Tabelle mit all diesen Daten mehrmals mit den bestimmten Daten an die Datumsdimension an, aber ich bekomme Wiederholungen und falsche Summen, als wenn ich meine laufen lasse ursprüngliche Abfrage, die die Aggregate in 2 separaten Abfragen mit unterschiedlichen where-Klauseln durchführt. Die Datumsdimensionstabelle enthält die Hauptdatumsspalte, der ich beitreten möchte. dann werde ich eine Datumspalte haben, auf der gefiltert werden soll, um alle Themen zu zählen. Ich möchte einen Datensatz für meinen ssrs-Bericht, den Sie sehen. –

+0

Ich frage mich, ob Union vielleicht der Weg ist, hier zu gehen? –

+0

Bitte beachten Sie meinen Kommentar zu Beitrag über –

0

Was Sie sehen, ist, dass, weil keine Ihrer Faktentabellen sich aufeinander beziehen, Sie im Wesentlichen ein kartesisches Produkt für die Faktentabellen erstellen - wo sie sich nur nach Datum beziehen.

diese vereinfachte Version Ihres Beispiel betrachte, wo ich einige Beispieldaten für „heute“ schließen auch ein:

CREATE TABLE #fact1 (id int identity, dt datetime, val varchar(5)); 
CREATE TABLE #fact2 (id int identity, dt datetime, val varchar(5)); 
CREATE TABLE #fact3 (id int identity, dt datetime, val varchar(5)); 
CREATE TABLE #fact4 (id int identity, dt datetime, val varchar(5)); 
CREATE TABLE #date (dt datetime, val varchar(5)); 
GO 

INSERT INTO #fact1 (dt, val) VALUES (GETDATE(),'fact1'); 
INSERT INTO #fact2 (dt, val) VALUES (GETDATE(),'fact2'); 
INSERT INTO #fact3 (dt, val) VALUES (GETDATE(),'fact3'); 
INSERT INTO #fact4 (dt, val) VALUES (GETDATE(),'fact4'); 
WAITFOR DELAY '00:00:01'; 
GO 5 

INSERT INTO #date (dt, val) VALUES (CAST(GETDATE() AS date),'Today'); 
GO 


SELECT * 
FROM #date d 
JOIN #fact1 AS f1 ON d.dt = CAST(f1.dt AS date) 
JOIN #fact2 AS f2 ON d.dt = CAST(f2.dt AS date) 
JOIN #fact3 AS f3 ON d.dt = CAST(f3.dt AS date) 
JOIN #fact4 AS f4 ON d.dt = CAST(f4.dt AS date); 
GO 

DROP TABLE #fact1; 
DROP TABLE #fact2; 
DROP TABLE #fact3; 
DROP TABLE #fact4; 
DROP TABLE #date; 
GO 

Beachten Sie, dass 625 Zeilen zurückgegeben werden. Dies ist das kartesische Produkt der vier Faktentabellen, das dann mit der Dimensionstabelle verknüpft wird. Dies geschieht, weil zwischen den Fakttabellen außer dem Datum keine Beziehung besteht. Als Ergebnis wird jede eine Zeile für "heute" in einer Faktentabelle mit jede Zeile für "heute" in jede andere Faktentabelle verbunden.

Betrachten Sie stattdessen, wie sich Ihre vier Faktentabellen OHNE den Join mit der Datumstabellen beziehen. Schreiben Sie Ihre Abfrage neu, damit die Daten vor dem Verbinden mit der Datumsdimension sinnvoll sind. Beziehen sich die Tabellen auf etwas wie eine order_id oder einen anderen Aspekt?

Wenn die Faktentabellen nur so sehr, beziehen sich, wie Sie sie nach Datum kumulieren - dann ja, müssen Sie eine andere Ansatz:

a) Aggregate nach Datum zuerst, dann kommen die aggregierten Sätze zusammen. Diese Option ist am sinnvollsten, wenn Sie nur die aggregierten Werte benötigen und nicht die vollständigen Details für Ihren Bericht benötigen.

b) Weisen Sie jedem Kalendertag eine beliebige Zeilennummer() zu und verwenden Sie diese als sekundäres Verknüpfungskriterium. Wenn sich die Daten nicht tatsächlich beziehen, funktioniert diese Option möglicherweise, aber die detaillierte Ergebnismenge ist weitgehend bedeutungslos, wenn sich alle Daten in einer einzelnen Zeile nicht auf eine einzelne Entität beziehen. Dies könnte Ihnen die richtigen Zahlen geben, ist aber logisch eine nutzlose Ergebnismenge.

SELECT * 
FROM #date d 
JOIN (SELECT *, 
     ROW_NUMBER() OVER(PARTITION BY CAST(dt AS date) ORDER BY dt) AS row_num 
     FROM #fact1) AS f1 ON d.dt = CAST(f1.dt AS date) 
JOIN (SELECT *, 
     ROW_NUMBER() OVER(PARTITION BY CAST(dt AS date) ORDER BY dt) AS row_num 
     FROM #fact2) AS f2 ON d.dt = CAST(f2.dt AS date) AND f1.row_num = f2.row_num 
JOIN (SELECT *, 
     ROW_NUMBER() OVER(PARTITION BY CAST(dt AS date) ORDER BY dt) AS row_num 
     FROM #fact3) AS f3 ON d.dt = CAST(f3.dt AS date) AND f1.row_num = f3.row_num 
JOIN (SELECT *, 
     ROW_NUMBER() OVER(PARTITION BY CAST(dt AS date) ORDER BY dt) AS row_num 
     FROM #fact4) AS f4 ON d.dt = CAST(f4.dt AS date) AND f1.row_num = f4.row_num 

c) Unterteilen Sie dies in separate Anweisungen: eine für jede Faktentabelle. Optional UNION diese Ergebnisse in einer einzigen Ergebnismenge. Diese Ergebnismenge könnte dann weiter aggregiert/gruppiert werden, um Ihnen die gewünschten Ergebnisse zu liefern.

SELECT *, 'Fact 1' AS SourceTable 
FROM #date d 
JOIN #fact1 AS f1 ON d.dt = CAST(f1.dt AS date) 
UNION ALL 
SELECT *, 'Fact 2' AS SourceTable 
FROM #date d 
JOIN #fact2 AS f2 ON d.dt = CAST(f2.dt AS date) 
UNION ALL 
SELECT *, 'Fact 3' AS SourceTable 
FROM #date d 
JOIN #fact3 AS f3 ON d.dt = CAST(f3.dt AS date) 
UNION ALL 
SELECT *, 'Fact 4' AS SourceTable 
FROM #date d 
JOIN #fact4 AS f4 ON d.dt = CAST(f4.dt AS date); 

Meiner Meinung nach, Optionen ein & c die besten Lösungen anzubieten, wenn die Faktentabellen sonst nicht miteinander in Beziehung stehen. Option b funktioniert möglicherweise, aber Sie müssen sehr vorsichtig sein, dass Ihre Daten aussagekräftig sind & erstellt keine verwirrenden oder fehlerhaften Ergebnisse.

Beachten Sie außerdem, dass die Anwendung einer Funktion auf ein Join-Kriterium (in diesem Fall CONVERT in der Datumsspalte) die Indexnutzung verhindert, was zu einem Tabellenscan führt.

+0

Ich habe schon Option a) angeschaut aber es werden immer noch falsche Zeilen für einen Test von zwei Datumstabellen gegeben. dh mocdate und senddate. Es gibt eine Fteam-Spalte, die die einzige Beziehung zwischen den beiden Tabellen darstellt. Also für Ihr Beispiel könnten Sie eine fteam-Spalte in jeder Faktentabelle hinzufügen und sehen, ob es funktioniert. Ich werde die row_number Lösung ausprobieren, sonst denke ich daran, eine Funktion zu verwenden, um die Anzahl der Bewertungen für ein bestimmtes Datum zurückzugeben und diese mit den anderen 3 Tabellen zu verbinden (erinnern Sie sich, dass diese Tabellen im Wesentlichen 1 Tabelle sind), Danke für Ihre Hilfe gibt mir einen Überblick, um es zu versuchen. –