none
Datensatz mit jüngstem Datum in einer anderen Tabelle ermitteln RRS feed

  • 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.StandortNr

    Dies 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


    Dienstag, 24. März 2015 12:52

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

    Dienstag, 24. März 2015 13:14
  • 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

    Dienstag, 24. März 2015 21:19

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



    Dienstag, 24. März 2015 12:54
    Moderator
  • 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.


    Dienstag, 24. März 2015 12:56
  • 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

    Dienstag, 24. März 2015 12:58
    Moderator
  • 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

    Dienstag, 24. März 2015 13:14
  • 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


    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=-2147217396

    Ein 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

    Dienstag, 24. März 2015 13:42
  • 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

    Dienstag, 24. März 2015 21:19
  • Danke Thomas und nochmals Danke an Christoph,

    habs mit Eurer Hilfe nun hinbekommen.

    Viele Grüße

    Patrick

    Mittwoch, 25. März 2015 07:50