Announcement

Collapse
No announcement yet.

SQL-Abfrage ohne first / last über mehrere Tabellen

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • SQL-Abfrage ohne first / last über mehrere Tabellen

    Hallo ihr,

    nachdem ich meine Access-Datenbank zum MS SQL Server 2008 Express migriert habe, funktioniert leider der SQL-Befehl "First" / "Last" nicht mehr. Ich habe jetzt verzweifelt überall im Internet nach einer Lösung gesucht, bin aber nicht wirklich weitergekommen. Irgendwie müßte es mit einem "Subselect" oder "Subquery" funktionieren - aber die bereits ausprobierten Codes gingen nicht.

    Zur Problemstellung:

    Ich habe eine Tabelle Personen, eine Tabelle PersEmail und eine Tabelle Emailadressen. In erster sind klar alle Personen, in zweiter eine M:N-Verknüpfung zwischen Personen und Emailadressen und in dritter die Emailadressen selbst.

    Bsp (vereinfacht):
    ----
    [Personen]
    [Felder: Pers_ID / Pers_Nachname / Pers_Vorname]
    1 / Meier / Karl
    2 / Huber / Heinz
    3 / Schmidt / Klaus
    4 / Meier / Claudia
    5 / Müller / Reiner
    ----
    [PersEmail]
    [Felder: PersEmail_ID / Pers_ID / Email_ID / Letzte_Änderung]
    1 / 1 / 1 / 01.01.2008
    2 / 3 / 2 / 20.10.2008
    3 / 1 / 3 / 30.10.2008
    4 / 2 / 4 / 21.10.2008
    5 / 4 / 1 / 02.01.2008
    ----
    [Emailadressen]
    [Felder: Email_ID / Email_Adresse]
    1 / [email protected]
    2 / [email protected]
    3 / [email protected]
    4 / [email protected]
    ----

    Was ich brauche ist die aktuelle Emailadresse der Person. Bis dato war das ganze nicht so schwierig. Alle drei Tabellen waren miteinander verknüpft, die M:N-Tabelle nach dem Datum der letzten Änderung der jeweiligen Verknüpfung absteigend sortiert und dann habe ich einfach mit "Erster Wert" die aktuellste Emailadresse rausgesucht.

    Bsp. gewünschtes Trefferergebnis:
    [Felder: Pers_ID / Pers_Nachname / Pers_ Vorname / Email_ID / Email_Adresse / Letzte_Änderung]
    1 / Meier / Karl / 3 / [email protected] / 30.10.2008
    2 / Huber / Heinz / 4 / [email protected] / 21.10.2008
    3 / Schmidt / Klaus / 2 / [email protected] / 20.10.2008
    4 / Meier / Claudia / 1 / [email protected] / 02.01.2008

    ----

    Mit dem SQL-Server funktioniert jetzt "First" und "Last" leider nicht mehr. Ich habe jetzt schon diverse Lösungen mit "Top 1" durch - allerdings bekomme ich dann immer nur die erste Person angezeigt. Alle Versuche das "TOP 1" irgendwo in den Code zu bringen um zu zeigen, dass ich nur bei der Emailadresse den ersten Wert angezeigt bekommen will half leider nicht.

    Wenn man mit einer Gruppierung arbeitet, dann kann man zwar bei "Letzte_Änderung" mit Max() den höchsten Wert herausfinden - allerdings muss man dann Email_ID auch mit in die Gruppierung reinnehmen. Nimmt man hier auch Max(), dann sucht er alphabetisch den höchsten oder niedrigsten Wert heraus (bei Min()). Wählt man bei der Email_ID hingegen Group by, dann tauchen im Trefferergebnis wieder alle Emailadressen der Person auf.

    Es wäre wirklich supergenial, wenn irgendjemand hier eine Lösung wüßte. An sich kann es keine große Sache sein.

    Stefan


    Hier der Code aus Access, der dort gut funktionierte:

    Code:
    SELECT   P.Pers_ID, First(P.Pers_Nachname) AS ErsterWertvonPers_Nachname, 
             First(P.Pers_Vorname) AS ErsterWertvonPers_Vorname, 
             First(E.Email_Letzte_Änderung) AS ErsterWertvonEmail_Letzte_Änderung, 
             First(E.Email_ID) AS ErsterWertvonEmail_ID, 
             First(E.Email_Adresse) AS ErsterWertvonEmail_Adresse 
    FROM     (PersEmail AS PE 
              RIGHT JOIN Personen AS P 
              ON PE.Pers_ID = P.Pers_ID) 
             LEFT JOIN Emailadressen AS E 
             ON PE.Email_ID = E.Email_ID 
    GROUP BY P.Pers_ID 
    ORDER BY P.Pers_ID, First(E.Email_Letzte_Änderung) DESC;

    Dann ein Code, der in einem anderen Forum vorgeschlagen wurde, mir aber nicht weitergeholfen hatte:

    Code:
    SELECT p.Pers_ID, p.Pers_Nachname, p.Pers_Vorname, e.Email_ID, e.Email_Adresse,
    (SELECT MAX(PersEmail_Letzte_Änderung) AS MaxvonPersEmail_Letzte_Änderung
    FROM dbo.PersEmail AS pe
    WHERE (Pers_ID = p.Pers_ID) AND (Email_ID = e.Email_ID)) AS Letzte_Änderung
    FROM dbo.Personen AS p 
    INNER JOIN dbo.Emailadressen AS e 
    ON p.Pers_ID = e.Pers_ID
    Speichern kann ich ihn aber nicht, weil es den letzten Ausdruck e.Pers_ID nicht gibt. In der Tabelle Emailadressen gäbe es höchstens Email_ID, aber die Email_ID und die Pers_ID hängen ja gerade nicht direkt miteinander zusammen.

    Eine andere Variante brachte mir die Fehlermeldung "Die Unterabfrage hat mehr als einen Wert zurückgegeben":

    Code:
    SELECT pers.Pers_ID, pers.Pers_Nachname, pers.Pers_Vorname, pers.Pers_Geburtsdatum, mail.Email_ID, mail.Email_Adresse
    FROM dbo.Personen AS pers CROSS JOIN dbo.Emailadressen AS mail
    WHERE (mail.Email_ID =
                 (SELECT Email_ID
                  FROM dbo.PersEmail AS persmail1
                  WHERE (Pers_ID = pers.Pers_ID) 
                  AND (PersEmail_Letzte_Änderung = 
                 (SELECT MAX(persmail2.persemail_letzte_änderung) AS Expr1
                  FROM dbo.PersEmail AS persmail2
                  WHERE (Pers_ID = pers.Pers_ID)))))
    Vielleicht sollte ich noch erwähnen, dass in jeder der drei Tabellen auch ein Timestamp-Feld vorhanden wäre (Email_Timestamp, Pers_Timestamp, PersEmail_Timestamp). Vielleicht könnte man statt mit dem Änderungsdatum auch damit arbeiten??

    Für diejenigen, die die Datenbank mal kurz nachstellen wollen häng ich einfach mal die drei besagten Tabellen mit Dummy-Datensätzen als txt-Dateien hier mit dran.

    Grüße

    Stefan
    Attached Files

  • #2
    Hallo Stefan,

    ein langer Thread, viel zu viel zu lesen

    Auch ich habe (und tue es noch) viel mit Access gearbeitet und da gehen Sachen, die eigentlich (besser) nicht gehen sollten und an die gewöhnt man sich dann; die muss man sich dann wie abgewöhnen.

    Als nicht ganz vollständiger Ansatz hier ein Bsp, wie Du die letzte/aktuelle Email-Adresse ermitteln kannst:

    [highlight=SQL]SELECT P.Pers_ID, P.Pers_Nachname, P.Pers_Vorname,
    (SELECT TOP 1 SE.Email_Adresse
    FROM PersEmail AS SP
    INNER JOIN
    Emailadressen AS SE
    ON SP.Email_ID = SE.Email_ID
    WHERE SP.Pers_ID = P.Pers_ID
    ORDER BY SP.Letzte_Änderung DESC) LastEmailAddress
    FROM Personen AS P[/highlight]

    Den aktuellsten Datensatz bekommt man über einen Subselect immer, indem man nach Datum DESC sortiert und dann nur mit TOP 1 den ersten Datensatz nimmt; eben dem FIRST.

    Die WHERE Bedingung vom Subselect könnte man auch in die JOIN Bedingung packen, ab so finde ich es verständlicher; der MSSQL behandelt es so oder so durch den Optimierer gleich.
    Zuletzt editiert von O. Helper; 01.11.2008, 07:16.
    Olaf Helper

    <Blog> <Xing>
    * cogito ergo sum * errare humanum est * quote erat demonstrandum *
    Wenn ich denke, ist das ein Fehler und das beweise ich täglich

    Comment

    Working...
    X