Benutzer mit den meisten Antworten
Datensatz mit jüngstem Datum in einer anderen Tabelle ermitteln

Frage
-
Hallo Zusammen,
ich befürchte ich stehe auf dem Schlauch und brächte mal Hilfe. Ich hoffe ich kann im folgenden mein - für mich komplexes - Problem richtig beschreiben.
ich habe eine Table-valued Function die mir Daten aus unterschiedlichen Tabellen liefert. Je nach Abfrage können das einige Tausend Datensätze sein.
Es gibt folgende Tabellen:
Tabelle1: beinhaltet Rechnungsdaten
Aufbau: VorgangNr, StandortNr; usw.
Tabelle2: Zeigt an wer Rechnungen welches Standortes errhalten soll und steht in 1:N Beziehung zu Tabelle1
Aufbau: VersandID;StandortNr;MitarbeiterNr, usw.
Das Problem ist nun
Tabelle3: Zeigt an, welche Rechnung bereits an wen versendet wurde. DIe Tabelle steht in 1:N Beziehung zu Tabelle1 und auch in 1:N Beziehung zu Tabelle2
LogID;VorgangNr,MitarbeiterNr, Versanddatum
Ich möchte gerne wissen, ob eine Rechnung aus Tabelle1 bereits an den Zuständigen Bearbeiter aus Tabelle 2 versendet wurde und wenn ja wann zuletzt. (Es kann durchaus sein, dass der Mitarbeiter die Rechnung bereits mehrfach erhalten hat.)
Zunächst habe ich versucht, das innerhalb der Abfrage durch eine Unterabfrage zu lösen:
SELECT TOP 100 PERCENT R.VorgangNr, E_S.MitarbeiterNr, R.StandortNr, L.LetzerLog
FROM AbfrageAufTabelle2 E_S LEFT OUTER JOIN
(SELECT VorgangNr, MitarbeiterNr, MAX(Versanddatum) AS LetzerLog
FROM dbo.Tabelle3
GROUP BY VorgangNr, MitarbeiterNr) L ON E_S.MitarbeiterNr = L.MitarbeiterNr RIGHT OUTER JOIN
AbfrageAufTabelle1 R ON L.VorgangNr = R.VorgangNr AND E_S.StandortNr = R.StandortNrDies liefert dann aber nur die Werte, die bereits einen Log haben. Die anderen Werte werden mir nicht angezeigt.
Dann habe ich versucht, das ganze durch eine Scalar_Valued-Function zu lösen die ich als weiteres Feld in die Table-valued Function einbaue. Das führte auch zum Erfolg, ist nur super langsam. Bei 100 Datensätzen geht es gerade noch. Danach wird die Abfrage einfach zu langsam.
Kann mich jemand mal auf die richtige Lösung schupsen?
Vielen Dank und viele Grüße
Patrick
- Bearbeitet Patrick Pohlmann Dienstag, 24. März 2015 12:57
Antworten
-
Meinst Du so etwas?
create Table #Tabelle1(VorgangNr int, StandortNr int); create Table #Tabelle2(VersandID int identity, StandortNr int, MitarbeiterNr int); create Table #Tabelle3(LogID int identity, VorgangNr int, MitarbeiterNr int, Versanddatum date); Insert into #Tabelle1(VorgangNr, StandortNr) Values (1, 1); Insert into #Tabelle1(VorgangNr, StandortNr) Values (2, 2); Insert into #Tabelle1(VorgangNr, StandortNr) Values (3, 1); Insert into #Tabelle2(StandortNr, MitarbeiterNr) Values (1, 10); Insert into #Tabelle2(StandortNr, MitarbeiterNr) Values (1, 11); Insert into #Tabelle2(StandortNr, MitarbeiterNr) Values (2, 20); Insert into #Tabelle2(StandortNr, MitarbeiterNr) Values (2, 21); Insert into #Tabelle3(VorgangNr, MitarbeiterNr, Versanddatum) Values(1, 10, '20150301'); Insert into #Tabelle3(VorgangNr, MitarbeiterNr, Versanddatum) Values(1, 10, '20150302'); Insert into #Tabelle3(VorgangNr, MitarbeiterNr, Versanddatum) Values(2, 20, '20150305'); /* Select * from #Tabelle1; Select * from #Tabelle2; Select * from #Tabelle3; */ -- Alle Rechnungen Select * from #Tabelle1 a Inner Join #Tabelle2 b on a.StandortNr = b.StandortNr Left Join #Tabelle3 c on a.VorgangNr = c.VorgangNr and b.MitarbeiterNr = c.MitarbeiterNr order by a.VorgangNr, a.StandortNr, b.MitarbeiterNr, c.Versanddatum; -- Nur die letzte Rechnung Select a.VorgangNr, b.MitarbeiterNr, max(c.Versanddatum) as Zuletzt_Versendet from #Tabelle1 a Inner Join #Tabelle2 b on a.StandortNr = b.StandortNr Left Join #Tabelle3 c on a.VorgangNr = c.VorgangNr and b.MitarbeiterNr = c.MitarbeiterNr group by a.VorgangNr, b.MitarbeiterNr order by VorgangNr, MitarbeiterNr, Zuletzt_Versendet; With LetzteRechnung as ( Select a.VorgangNr, b.MitarbeiterNr, max(c.Versanddatum) as Zuletzt_Versendet from #Tabelle1 a Inner Join #Tabelle2 b on a.StandortNr = b.StandortNr Left Join #Tabelle3 c on a.VorgangNr = c.VorgangNr and b.MitarbeiterNr = c.MitarbeiterNr group by a.VorgangNr, b.MitarbeiterNr ) Select a1.VorgangNr, a1.StandortNr, lr.MitarbeiterNr, lr.Zuletzt_Versendet from #Tabelle1 a1 Left Join LetzteRechnung lr on a1.VorgangNr = lr.VorgangNr; go drop table #Tabelle1; drop table #Tabelle2; drop table #Tabelle3;
Einen schönen Tag noch,
Christoph
--
Microsoft SQL Server MVP - http://www.insidesql.org/blogs/cmu- Als Antwort markiert Patrick Pohlmann Mittwoch, 25. März 2015 07:49
-
Hi Patrick,
für den letzten Wert bzw. jüngstes Datum nehme ich einen View
SELECT TOP (1) DatumUhrzeit, FROM dbo.table AS LogTable ORDER BY DatumUhrzeit Desc
Das nur die Werte angezeigt werden, die bereits einen Log Eintrag haben liegt an dem Left outer Join auf Tabelle 2. Ich glaube, dass müsste Tabelle 1 rein. Das würde bedeuten aus Tabelle 1 alle Werte, die Werte aus Tabelle 2 mit left outer join anbinden und den letzen Eintrag ebenfalls mit einem left Outer Join aus Tabelle 3 lesen. Gibt dann Null in dem Feld, wenn kein Eintrag da ist oder sonst den letzten Eintrag, so du obigen Select verwendest.
Hoffe, konnte dir etwas weiterhelfen.
Viele Grüße
Thomas
- Als Antwort markiert Patrick Pohlmann Mittwoch, 25. März 2015 07:49
Alle Antworten
-
Hallo Patrick,
es gibt keinen auslesbaren "letzten" Wert, nur einen größten.
SELECT MAX( <Spaltenname> ) AS Aliasname FROM <Tabelle> WHERE ...
Um dir besser helfen zu können, wäre es aber hilfreich, wenn Du deine Tabellenstruktur als CREATE TABLE Statements, die Beispieldaten als INSERT INTO Statements und deine Funktion eben als komplettes SQL Statement posten würdest.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community
- Bearbeitet Stefan FalzModerator Dienstag, 24. März 2015 12:56
-
Ja, sorry. Die Überschrift war etwas mißverständlich. Wie Du aber siehst, habe ich ja bereits mit MAX in meiner Abfrage gearbeitet.
Ich habe versucht meine Komplexe Abfrage zu vereinfachen. Die ganze Sicht wäre arg komplex. Vor allem weil die Daten aus vielen weiteren Tabellen kommen.
- Bearbeitet Patrick Pohlmann Dienstag, 24. März 2015 12:59
-
Hallo Patrick,
dann bitte, wie oben geschrieben, alle relevanten Bestandteile (Tabellen, Beispieldaten, bisherige Funktion) als SQL Statements hier posten und das gewünschte Ergebnis aus den Beispieldaten noch exakt aufführen.
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET
http://www.asp-solutions.de/ - Consulting, Development
http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community -
Meinst Du so etwas?
create Table #Tabelle1(VorgangNr int, StandortNr int); create Table #Tabelle2(VersandID int identity, StandortNr int, MitarbeiterNr int); create Table #Tabelle3(LogID int identity, VorgangNr int, MitarbeiterNr int, Versanddatum date); Insert into #Tabelle1(VorgangNr, StandortNr) Values (1, 1); Insert into #Tabelle1(VorgangNr, StandortNr) Values (2, 2); Insert into #Tabelle1(VorgangNr, StandortNr) Values (3, 1); Insert into #Tabelle2(StandortNr, MitarbeiterNr) Values (1, 10); Insert into #Tabelle2(StandortNr, MitarbeiterNr) Values (1, 11); Insert into #Tabelle2(StandortNr, MitarbeiterNr) Values (2, 20); Insert into #Tabelle2(StandortNr, MitarbeiterNr) Values (2, 21); Insert into #Tabelle3(VorgangNr, MitarbeiterNr, Versanddatum) Values(1, 10, '20150301'); Insert into #Tabelle3(VorgangNr, MitarbeiterNr, Versanddatum) Values(1, 10, '20150302'); Insert into #Tabelle3(VorgangNr, MitarbeiterNr, Versanddatum) Values(2, 20, '20150305'); /* Select * from #Tabelle1; Select * from #Tabelle2; Select * from #Tabelle3; */ -- Alle Rechnungen Select * from #Tabelle1 a Inner Join #Tabelle2 b on a.StandortNr = b.StandortNr Left Join #Tabelle3 c on a.VorgangNr = c.VorgangNr and b.MitarbeiterNr = c.MitarbeiterNr order by a.VorgangNr, a.StandortNr, b.MitarbeiterNr, c.Versanddatum; -- Nur die letzte Rechnung Select a.VorgangNr, b.MitarbeiterNr, max(c.Versanddatum) as Zuletzt_Versendet from #Tabelle1 a Inner Join #Tabelle2 b on a.StandortNr = b.StandortNr Left Join #Tabelle3 c on a.VorgangNr = c.VorgangNr and b.MitarbeiterNr = c.MitarbeiterNr group by a.VorgangNr, b.MitarbeiterNr order by VorgangNr, MitarbeiterNr, Zuletzt_Versendet; With LetzteRechnung as ( Select a.VorgangNr, b.MitarbeiterNr, max(c.Versanddatum) as Zuletzt_Versendet from #Tabelle1 a Inner Join #Tabelle2 b on a.StandortNr = b.StandortNr Left Join #Tabelle3 c on a.VorgangNr = c.VorgangNr and b.MitarbeiterNr = c.MitarbeiterNr group by a.VorgangNr, b.MitarbeiterNr ) Select a1.VorgangNr, a1.StandortNr, lr.MitarbeiterNr, lr.Zuletzt_Versendet from #Tabelle1 a1 Left Join LetzteRechnung lr on a1.VorgangNr = lr.VorgangNr; go drop table #Tabelle1; drop table #Tabelle2; drop table #Tabelle3;
Einen schönen Tag noch,
Christoph
--
Microsoft SQL Server MVP - http://www.insidesql.org/blogs/cmu- Als Antwort markiert Patrick Pohlmann Mittwoch, 25. März 2015 07:49
-
Hallo Christoph,
wow, Du hast die Beispieldaten ja schneller erstellt als ich mir überhaupt vorstellen könnte zu tippen.
Deine Lösung funktioniert in den Beispieldaten. Ich muss jetzt nur erstmal verstehen was Du da machst. Die Sache mit "With" hab ich vorher noch nie gesehen bzw. gemacht.
Ist das das gleich wie wenn ich die Abfragen verschachtel? Also so:
Select A.* FROM (SELECT * from DeineWithAbfrage) A
Auf jeden Fall erstmal vielen Dank!
Viele Grüße
Patrick
- Bearbeitet Patrick Pohlmann Dienstag, 24. März 2015 13:39
-
Hallo Patrick,
das ist eine Common Table Expression (CTE):
Gibt es seit 2005:
https://technet.microsoft.com/de-de/library/ms190766%28v=sql.105%29.aspx?f=255&MSPPError=-2147217396Ein allgemeiner Tabellenausdruck (Common Table Expression oder CTE) kann als temporäres Resultset betrachtet werden, das im Ausführungsbereich einer einzigen SELECT-, INSERT-, UPDATE-, DELETE- oder CREATE VIEW-Anweisung definiert wird. Ein allgemeiner Tabellenausdruck ähnelt einer abgeleiteten Tabelle dahingehend, dass er nicht als Objekt gespeichert wird und nur für die Dauer der Abfrage vorhanden ist. Im Gegensatz zu einer abgeleiteten Tabelle kann ein allgemeiner Tabellenausdruck auf sich selbst verweisen, und es können in der gleichen Abfrage mehrere Verweise auf ihn vorhanden sein.
Einen schönen Tag noch,
Christoph
--
Microsoft SQL Server MVP - http://www.insidesql.org/blogs/cmu -
Hi Patrick,
für den letzten Wert bzw. jüngstes Datum nehme ich einen View
SELECT TOP (1) DatumUhrzeit, FROM dbo.table AS LogTable ORDER BY DatumUhrzeit Desc
Das nur die Werte angezeigt werden, die bereits einen Log Eintrag haben liegt an dem Left outer Join auf Tabelle 2. Ich glaube, dass müsste Tabelle 1 rein. Das würde bedeuten aus Tabelle 1 alle Werte, die Werte aus Tabelle 2 mit left outer join anbinden und den letzen Eintrag ebenfalls mit einem left Outer Join aus Tabelle 3 lesen. Gibt dann Null in dem Feld, wenn kein Eintrag da ist oder sonst den letzten Eintrag, so du obigen Select verwendest.
Hoffe, konnte dir etwas weiterhelfen.
Viele Grüße
Thomas
- Als Antwort markiert Patrick Pohlmann Mittwoch, 25. März 2015 07:49