tutorials.de Buch-Aktion 02/2012
ERLEDIGT
NEIN
ANTWORTEN
9
ZUGRIFFE
515
EMPFEHLEN
  • An Twitter übertragen
  • An Facebook übertragen
AUF DIESES THEMA
ANTWORTEN
  1. #1
    janw janw ist offline Mitglied Silber
    Registriert seit
    May 2005
    Ort
    Bremen
    Beiträge
    56
    Hallo zusammen,

    ich habe folgendes Szenario: Eine Stammdaten-Tabelle mit Benutzern, die Aktionen ausführen können, und eine Tabelle mit konkreten, ausgeführten Aktionen dieser Benutzer mit der Fremdschlüssel-Beziehung, dass jede Aktion zu genau einem Benutzer gehört. Vereinfacht:
    BENUTZER(id NUMBER, name VARCHAR(30))
    AKTION(id NUMBER, ben_id NUMBER, zeitpunkt DATE, beschreibung VARCHAR(30), ...noch ein paar weitere Spalten)

    Mein Ziel ist nun, mit einer Abfrage alle Benutzer zusammen mit Zeitpunkt und Beschreibung ihrer aktuellsten Aktion zu erhalten. Falls ein Benutzer noch keine Aktion ausgeführt hat, sollen Nullwerte verwendet werden. Es sollte examplarisch also etwa so aussehen (zeigt Benutzer 4711 und 42 mit ihren zuletzt ausgef. Aktionen, Benutzer 23 ist noch ohne Aktion):

    Spalten: (Benutzer.id, Benutzer.name, Aktion.zeitpunkt, Aktion.beschreibung)
    (4711, Peter, 01.08.2005 11:12, Neue Aktion)

    (42, James, 22.07.2005 22:30, Andere Aktion)

    (23, LazyJoe, NULL, NULL)


    Ich kann dieses Problem lösen: mit UNION, das die Menge der Benutzer mit bereits mind. einer Aktion vereint mit der Menge von Benutzern ohne Aktionen.

    Meine Frage ist jetzt, ob es für dieses nicht außergeöhnliche Problem nicht eine elegantere/perfomantere Lösung gibt?!

    Hier ist die Abfrage:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    SELECT b.name, a.id, a.zeitpunkt
          FROM aktion a, benutzer b
          WHERE a.ben_id = b.id 
          AND a.zeitpunkt = 
              (select max(a2.zeitpunkt) from aktion a2 where a2.ben_id = b.id)
          UNION 
          SELECT b.name, to_number(null), to_date(null)
          FROM benutzer b
          WHERE NOT EXISTS(
              select *
              FROM aktion a
              WHERE a.ben_id = b.id
              )
              ORDER BY 1;


    Für Ideen dazu sehr dankbar...

    Gruß
    Jan
     

  2. #2
    Registriert seit
    Apr 2002
    Ort
    HH
    Beiträge
    3.224
    Ich bin mir nicht sicher, ob ich Dich richtig verstanden habe (Dein Query verwirrt mich), aber für mich schreit Deine Beschreibung nach einem LEFT JOIN:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    SELECT 
      b.name, 
      a.id, 
      a.zeitpunkt
    FROM benutzer AS b
    LEFT JOIN aktion AS a
      ON a.ben_id=b.id
    WHERE 
      a.zeitpunkt = (
        SELECT 
          MAX(a2.zeitpunkt)
        FROM aktion AS a2 
        WHERE a2.ben_id = b.id
      )
    Ist es das?

    Gruß hpvw
     
    Warum gibt (fast) keiner im Datenbankforum an, welches DBMS er benutzt?
    Ich gehe im Zweifelsfall ohne Nachfrage von MySQL > 4.1 i.V.m. PHP aus.
    Gewöhnt euch bitte auch an, die Fehlermeldung von mysql_error() zu posten.

  3. #3
    janw janw ist offline Mitglied Silber
    Registriert seit
    May 2005
    Ort
    Bremen
    Beiträge
    56
    Hi,
    danke für den Vorschlag. Das DBMS ist Oracle 8.1.7. Daher sieht der LEFT JOIN unten auch ein wenig altertümlich aus.
    Wenn ich die Abfrage so ausführe, bekomme ich nur die Benutzer, die auch eine Aktion ausgeführt haben - anscheinend wegen der Bedingung
    WHERE a.zeitpunkt = (SELECT ...,
    die ja nicht zutrifft.
    Ich möchte aber alle Benutzer bekommen...

    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
       SELECT b.name, a.id, a.zeitpunkt
       FROM benutzer b, aktion a
       WHERE  (a.ben_id(+) = b.id) AND
         a.zeitpunkt = (
        SELECT 
          MAX(a2.zeitpunkt)
          FROM aktion a2 
          WHERE a2.ben_id = b.id
         );
     

  4. #4
    Registriert seit
    Apr 2002
    Ort
    HH
    Beiträge
    3.224
    Ist das einfache Verknüpfen mit Komma bei Oracle ein LEFT JOIN?
    Trotz allem habe ich natürlich etwas vergessen, sorry.
    Bei dem WHERE sollte man natürlich noch etwas ergänzen:
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
       WHERE  (a.ben_id(+) = b.id) AND (
         a.zeitpunkt = (
        SELECT 
          MAX(a2.zeitpunkt)
          FROM aktion a2 
          WHERE a2.ben_id = b.id
         )
         OR a.zeitpunkt IS NULL [COLOR=DarkGreen]# <-Auf Oracle-Syntax ggf. anpassen[/COLOR]
       );
    Das funktioniert natürlich nur sicher, wenn a.zeitpunkt ein "NOT-NULL-Feld" ist.

    Gruß hpvw
     
    Warum gibt (fast) keiner im Datenbankforum an, welches DBMS er benutzt?
    Ich gehe im Zweifelsfall ohne Nachfrage von MySQL > 4.1 i.V.m. PHP aus.
    Gewöhnt euch bitte auch an, die Fehlermeldung von mysql_error() zu posten.

  5. #5
    janw janw ist offline Mitglied Silber
    Registriert seit
    May 2005
    Ort
    Bremen
    Beiträge
    56
    Yes,
    wenn mich nicht alles täuscht, dann war das der entscheidende Tipp. Vielen Dank!

    Zu deiner Anmerkung:
    > Das funktioniert natürlich nur sicher, wenn a.zeitpunkt ein "NOT-NULL-Feld" ist.

    Verstehe ich dich richtig: Falls a.zeitpunkt NULL-Werte zulässt, und für Benutzer 4711 eine Aktion / nur Aktionen ohne Zeitpunkt eingetragen ist/sind, dann sähe es so aus, als ob Benutzer 4711 noch keine Aktionen ausgeführt hätte. ?

    Zur Oracle-Syntax:
    Das Komma bildet wie z.B. bei mysql auch das Kreuzprodukt zwischen zwei Tabellen.
    Der LEFT JOIN kommt (AFAIK nur bis 8.1.7) durch (+) zustande, wie bei
    (a.ben_id(+) = b.id).

    Gruß
    Jan
     

  6. #6
    Registriert seit
    Apr 2002
    Ort
    HH
    Beiträge
    3.224
    Zitat Zitat von janw
    Verstehe ich dich richtig: Falls a.zeitpunkt NULL-Werte zulässt, und für Benutzer 4711 eine Aktion / nur Aktionen ohne Zeitpunkt eingetragen ist/sind, dann sähe es so aus, als ob Benutzer 4711 noch keine Aktionen ausgeführt hätte. ?
    In dem Fall sollte sowohl die Zeile mit der letzten Aktion, als ich die Zeilen, in denen a.zeitpunkt NULL ist in die Ergebnistabelle aufgenommen werden, sofern zu dem Benutzer Zeilen mit NULL-Werten existieren.

    Zitat Zitat von janw
    Zur Oracle-Syntax:
    Das Komma bildet wie z.B. bei mysql auch das Kreuzprodukt zwischen zwei Tabellen.
    Der LEFT JOIN kommt (AFAIK nur bis 8.1.7) durch (+) zustande, wie bei
    (a.ben_id(+) = b.id).
    Die Syntax ist ja etwas kryptisch. Das kleine Plus habe ich gar nicht gesehen, sorry für die überflüssigen Kommentare.

    Gruß hpvw
     
    Warum gibt (fast) keiner im Datenbankforum an, welches DBMS er benutzt?
    Ich gehe im Zweifelsfall ohne Nachfrage von MySQL > 4.1 i.V.m. PHP aus.
    Gewöhnt euch bitte auch an, die Fehlermeldung von mysql_error() zu posten.

  7. #7
    Avatar von Nico Graichen
    Nico Graichen Nico Graichen ist offline aka gemballa
    tutorials.de Moderator
    Registriert seit
    Dec 2003
    Ort
    Pulheim (NRW)
    Beiträge
    3.883
    Blog-Einträge
    34
    Hi,

    ich kann mich täuschen, aber in 8.1.7 sollte auch der Left-Join auch direkt mit dem Begriff funktionieren und nicht nur mit dem (+). Soweit ich weiß, sind die Koin-Begriffe SQL-spezifisch und nicht DBMS-spezifisch.
    Wie gesagt, ich kann mich täuschen, aber ich bin der Meinung, dass es damit auch funktioniert.
    Bitte um Richtigstellung, falls es nicht so sein sollte.
     
    Grüße Nico
    ----------------------
    Xing
    ----------------------
    Zitat Zitat von Mark Twain (1835-1910)
    Es gibt drei Dinge, die eine Frau aus dem Nichts hervorzaubern kann: einen Hut, einen Salat und einen Ehekrach.
    Zitat Zitat von Mike Wilson - Biographie über Larry Ellison (CEO Oracle)
    The Difference Between God and Larry Ellison: God Doesn't Think He's Larry Ellison

  8. #8
    Registriert seit
    Apr 2002
    Ort
    HH
    Beiträge
    3.224
    Bleibt nur die Frage, welches DBMS die in SQL definierten Befehle so implementiert, wie sie definiert sind. Jedes DBMS hat halt irgendwo Abweichungen oder Erweiterungen von der allgemeinen Definition in seinem Dialekt. Die Ähnlichkeit ist aber dank des Standards zumindest so hoch, dass man sich schnell in ein anderes DBMS einarbeiten kann.

    Gruß hpvw
     
    Warum gibt (fast) keiner im Datenbankforum an, welches DBMS er benutzt?
    Ich gehe im Zweifelsfall ohne Nachfrage von MySQL > 4.1 i.V.m. PHP aus.
    Gewöhnt euch bitte auch an, die Fehlermeldung von mysql_error() zu posten.

  9. #9
    Avatar von Exceptionfault
    Exceptionfault Exceptionfault ist offline Mitglied Brokat
    Registriert seit
    Sep 2004
    Ort
    Neckarsulm
    Beiträge
    348
    Keywords wie INNER JOIN, LEFT JOIN oder FULL OUTER JOIN sind im sog. ANSI SQL/92 Standard definiert den mittlerweile jede "SQL konforme" Datenbank aus konsequent umsetzen sollte (sofern die erwähnten Features auch unterstützt werden).

    Auf Grund des Alters ist Oracle in der Version 8.1.7 nur SQL/86 (od. SQL/89?) konform. Daher die etwas umständliche Syntax mit dem (+).
    In einem Join die beiden Tabellen mit Komma zu verknüpfen ist übrigens auch nicht mehr ANSI konform, wird jedoch i.d.R. als INNER JOIN interpretiert, sofern in der WHERE Klausel die entsprechenden Bedingungen gesetzt sind. Ansonsten entsteht ein Kartesisches Produkt.
    Mittlerweile sind wir beim SQL/2003 Standard der u.a. XML integriert und Mengenoperationen wie MERGE und MULTISET.
     
    liebe Grüße
    Exceptionfault (http://exceptionfault.de)

    Never say: "Always"! Always say: "Never say never"! - Tom Kyte @ Ask Tom Live in Berlin 2008

  10. #10
    janw janw ist offline Mitglied Silber
    Registriert seit
    May 2005
    Ort
    Bremen
    Beiträge
    56
    Hi,
    ärgerlich wird's dann, wenn die SQL-Statements fest im Code sind und man wegen einer Umstellung von 8.1.7 auf 9i die SQL-Statements anpassen muss und den Code neu deployen muss...kurzfristig gedacht :(

    Danke f. die rege Beteiligung

    Gruß
    Jan
     

Ähnliche Themen

  1. MySQL 1:n Beziehung in einer Zeile
    Von MarcJ im Forum Relationale Datenbanksysteme
    Antworten: 2
    Letzter Beitrag: 01.06.10, 12:20
  2. oracle: Abfrage aus einer n zu m Beziehung
    Von BastianX75 im Forum Relationale Datenbanksysteme
    Antworten: 5
    Letzter Beitrag: 09.10.08, 10:38
  3. AND Abfrage innerhalb einer m:n Beziehung
    Von CObject im Forum Relationale Datenbanksysteme
    Antworten: 1
    Letzter Beitrag: 26.12.06, 20:10
  4. Maximalwert einer Spalte ermitteln
    Von Hektik im Forum Relationale Datenbanksysteme
    Antworten: 6
    Letzter Beitrag: 09.06.06, 00:49
  5. maximalwert in C ermitteln!!
    Von LatschFOB im Forum C/C++
    Antworten: 10
    Letzter Beitrag: 16.10.03, 19:52