Ausgehend von folgenden Daten:
create table #histories
(
username varchar(10),
account varchar(10),
assigned date
);
insert into #histories
values
('PHIL','ACCOUNT1','2017-01-04'),
('PETER','ACCOUNT1','2017-01-15'),
('DAVE','ACCOUNT1','2017-03-04'),
('ANDY','ACCOUNT1','2017-05-06'),
('DAVE','ACCOUNT1','2017-05-07'),
('FRED','ACCOUNT1','2017-05-08'),
('JAMES','ACCOUNT1','2017-08-05'),
('DAVE','ACCOUNT2','2017-01-02'),
('PHIL','ACCOUNT2','2017-01-18'),
('JOSH','ACCOUNT2','2017-04-08'),
('JAMES','ACCOUNT2','2017-04-09'),
('DAVE','ACCOUNT2','2017-05-06'),
('PHIL','ACCOUNT2','2017-05-07') ;
... die angibt, wann ein bestimmter Benutzer einem Konto zugewiesen wurde.
Ich möchte feststellen, wem am letzten Tag eines jeden Monats ein bestimmtes Konto gehörte (das zugewiesene Datum ist das Datum, an dem das Konto das Eigentum übertragen hat), wobei alle fehlenden Monatsenden ausgefüllt sind (möglicherweise erstellt aus einer handlichen dates
Tabelle, die ich zur Verfügung habe). mit nützlichen Spalten DateKey
, Date
und LastDayOfMonth
[ mit freundlicher Genehmigung von @AaronBertrand]) 1 .
Die gewünschten Ergebnisse wären:
PETER, ACCOUNT1, 2017-01-31
PETER, ACCOUNT1, 2017-02-28
DAVE, ACCOUNT1, 2017-03-31
DAVE, ACCOUNT1, 2017-04-30
FRED, ACCOUNT1, 2017-05-31
FRED, ACCOUNT1, 2017-06-30
FRED, ACCOUNT1, 2017-07-31
JAMES, ACCOUNT1, 2017-08-31
PHIL, ACCOUNT2, 2017-01-31
PHIL, ACCOUNT2, 2017-02-28
PHIL, ACCOUNT2, 2017-03-31
JAMES, ACCOUNT2, 2017-04-30
PHIL, ACCOUNT2, 2017-05-31
Den ersten Teil mit einer Fensterfunktion zu machen, ist trivial. Es fügt die "fehlenden" Zeilen hinzu, mit denen ich zu kämpfen habe.
2017-05
weil er es hatte2017-05-07
und es keinen nachfolgenden Inhaber gab?Antworten:
Ein Ansatz für dieses Problem besteht darin, Folgendes zu tun:
LEAD
auf SQL Server 2008. Sie können hierfürAPPLY
oder eine Abfrage verwenden.Ich habe Ihre Testdaten ein wenig modifiziert, um die Ergebnisse deterministisch zu machen. Fügte auch einen Index hinzu:
Hier ist die faulste Datumsdimensionstabelle aller Zeiten:
Für Schritt 1 gibt es viele Möglichkeiten zum Emulieren
LEAD
. Hier ist eine Methode:Für Schritt 2 müssen wir die NULL-Werte in etwas anderes ändern. Sie möchten den letzten Monat für jedes Konto angeben, daher ist es ausreichend, einen Monat zum Startdatum hinzuzufügen:
Für Schritt 3 können wir uns der Datumsdimensionstabelle anschließen. Die Spalte aus der Dimensionstabelle entspricht genau der Spalte, die Sie für die Ergebnismenge benötigen:
Ich mochte die Frage nicht, die ich bekam, als ich alles zusammenstellte. Beim Kombinieren von
OUTER APPLY
und kann es zu Problemen mit der Verknüpfungsreihenfolge kommenINNER JOIN
. Um die gewünschte Join-Reihenfolge zu erhalten, habe ich sie mit einer Unterabfrage umgeschrieben:Ich weiß nicht, wie viele Daten Sie haben, sodass es für Sie möglicherweise keine Rolle spielt. Aber der Plan sieht so aus, wie ich es möchte:
Die Ergebnisse stimmen mit Ihren überein:
quelle
Hier verwende ich keine Kalendertabelle, sondern eine natürliche Nummerntabelle nums.dbo.nums (Ich hoffe, Sie haben es auch, wenn nicht, kann es leicht generiert werden)
Ich habe die Antwort etwas anders als Ihre ('JOSH' <-> 'JAMES'), weil Ihre Daten diese 2 Zeilen enthalten:
mit dem gleichen Konto und zugewiesenem Datum und Sie haben nicht genau angegeben, welches genommen werden soll, ist diese Situation.
quelle
Dies ist auf keinen Fall eine sauber aussehende Lösung, aber es scheint die Ergebnisse zu liefern, die Sie suchen (ich bin sicher, dass andere nette, saubere, vollständig optimierte Abfragen für Sie haben werden).
quelle
Ich habe die Datumsdimensionstabelle von Aaron Bertrand verwendet, wie Sie auch in Ihrer Frage erwähnt haben (die für solche Szenarien eine sehr praktische Tabelle ist), und ich habe den folgenden Code geschrieben:
Ich habe die
EndOfMonth
Spalte der#dim
Tabelle (direkt nach derFirstOfMonth
Spalte) mit folgendem Code hinzugefügt :Und die Lösung:
quelle
Triangle JOIN für den Gewinn!
Ergebnisse sind:
Interaktiver Ausführungsplan hier.
E / A- und ZEIT-Statistik (alle Nullwerte nach logischen Lesevorgängen abgeschnitten):
Abfrage zum Erstellen der erforderlichen temporären Tabellen und Testen der von mir vorgeschlagenen T-SQL-Anweisung:
quelle