1. Willkommen im Forum für alle Datenbanken! Registriere Dich kostenlos und diskutiere über DBs wie Mysql, MariaDB, Oracle, Sql-Server, Postgres, Access uvm
    Information ausblenden

UNION

Dieses Thema im Forum "Microsoft Access" wurde erstellt von Nina123456, 23 Juni 2013.

  1. Nina123456

    Nina123456 Neuer Benutzer

    Hallo [​IMG]

    In meiner Datenbank geht es um Schiffe und Schleusungen m:n. Ich muss mit einem SQL Editor folgende Abfrage für die angelegte Datenbank formulieren:

    Listen Sie alle Schiffe mit Name und Art auf und ermitteln Sie jeweils die Anzahl an verschiedenen Schleusen, die sie bisher durchfahren haben ( als Ergebnisspalte "AnzahlSchleusungen"). Verwenden Sie die GROUP BY Funktion, um die Ergebnisse bezogen auf das Schiff ( Name ) auszugeben. Bei Schiffen, die noch keine Schleuse durchfahren haben, soll die Anzahl an durchfahrenen Schleusen mit einer Null versehen werden ( UNION Operator).

    Nicht besonders schwer, wenn denn der letzte Satz nicht wäre...habe jetzt schon so viel über diesen UNION Operator gelesen aber es wird leider nichts...
    hier ist mein Vorschlag, der jedoch nicht funktioniert
    zuerst die Tabellen mit den entsprechenden Attributen

    Schiff

    schf_id
    schf_name
    schf_art

    Schleuse
    schl_id
    schl_name

    durchfaehrt
    df_id
    df_schf_id
    df_schl_id

    SELECT schf_name, schf_art, COUNT( schl_id ) AS AnzahlSchleusen
    FROM Schiff, Schleuse, durchfaehrt
    WHERE ( schf_id LIKE df_schf_id AND df_schl_id LIKE schl_id)
    HAVING AnzahlSchleusen IS NOT NULL
    UNION
    SELECT schf_name, schf_art, COUNT( schl_id ) AS AnzahlSchleusen
    FROM Schiff, Schleuse, durchfaehrt
    WHERE ( schf_id LIKE df_schf_id AND df_schl_id LIKE schl_id )
    HAVING AnzahlSchleusen IS NULL
    GROUP BY schf_name, schf_art;

    wenn ich die Zeilen ab UNION weglasse, dann gibt er mir nur die Schiffe mit vorhandenen Schleusenvorgängen an, jedoch nicht die Schiffe, die noch nicht durch Schleusen gefahren sind....füge ich diese aber ein, dann funktioniert es nicht mehr
    Ich meine auch gelesen zu haben, dass die count funktion die Ergebnisse mit 0 nicht anzeigt


    Vielen Dank schonmal [​IMG])))

    lg Nina
     
  2. akretschmer

    akretschmer Datenbank-Guru

    Warum so umständlich?

    Code:
    test=*# select * from schiff;
     id |   name
    ----+----------
      1 | schiff 1
      2 | schiff 2
      3 | schiff 3
    (3 rows)
    
    Time: 0,232 ms
    test=*# select * from schleuse ;
     id |    name
    ----+------------
      1 | schleuse 1
      2 | schleuse 2
    (2 rows)
    
    Time: 0,164 ms
    test=*# select * from durchfahrt ;
     schiff | schleuse
    --------+----------
          1 |        1
          1 |        2
          2 |        2
    (3 rows)
    
    Time: 0,157 ms
    test=*# select a.name, count(d.*) from schiff a left join durchfahrt d on a.id=d.schiff group by a.name;
       name   | count
    ----------+-------
     schiff 1 |     2
     schiff 3 |     0
     schiff 2 |     1
    (3 rows)
    
     
  3. akretschmer

    akretschmer Datenbank-Guru

    • warum arbeitest Du mit LIKE? Das ist absolut uncool hier und kann Dir erheblich das Resultat der Abfrage fälschen
    • vermutlich sind Deine ID-Spalten Text oder sowas, auch uncool
    • Du joins die Tabelle schleuse, die aber in Resultat gar keine Rolle spielt, unsinnig
     
  4. Nina123456

    Nina123456 Neuer Benutzer

    Hallo :) erstmal danke für die schnellen Antworten,
    die ABfrage ist eine Vorgabe, wir müssen also auf jeden fall den UNION Operator verwenden und auf keinen Fall JOIN Ausdrücke
    Mein neuer Vorschlag:
    SELECT schf_name, schf_kategorie, COUNT( df_schl_id ) AS [AnzahlSchleusen]
    FROM Schiff, Schleuse, durchfaehrt
    WHERE ( schf_id = df_schf_id AND df_schl_id = schl_id)

    GROUP BY schf_name, schf_kategorie
    [[[[hier gibt er nur die Schiffe raus, die bereits durch eine schleuse gefahren sind und mit UNION sollte er dann die restlichen Schiffe anzeigen, die eben keine schleusung hatten]]]]

    UNION
    SELECTschf_name, schf_kategorie, COUNT( df_schl_id ) AS [AnzahlSchleusen]
    FROM Schiff, Schleuse, durchfaehrt
    WHERE ( AnzahlSchleusen IS NULL AND schf_id = df_schf_id AND df_schl_id = schl_id)
    GROUP BY schf_name, schf_kategorie;
     
  5. Nina123456

    Nina123456 Neuer Benutzer

    SELECT schf_name, schf_kategorie, COUNT( df_schl_id ) AS [AnzahlSchleusen]
    FROM Schiff, Schleuse, durchfaehrt
    WHERE ( schf_id = df_schf_id AND df_schl_id = schl_id AND schf_id IN( SELECT df_schf_id FROM durchfaehrt))
    GROUP BY schf_name, schf_kategorie
    UNION
    SELECT schf_name, schf_kategorie, COUNT (df_schl_id) AS [AnzahlSchleusen]
    FROM Schiff, Schleuse, durchfaehrt
    WHERE ( df_schl_id = schl_id AND schf_id = df_schf_id AND schf_id IN ( SELECT df_schf_id FROM durchfaehrt))
    GROUP BY schf_name, schf_kategorie;

    hier gibt er mir trotzdem nur die geschleusten Schiffe raus
     
  6. akretschmer

    akretschmer Datenbank-Guru

    Die Forderung, keinen JOIN zu verwenden, ist Bullshit. Auch wenn Du die Syntax ohne expliziete JOINs nutzt verwendest Du impliziete Joins, die Datenbank macht in beiden Fällen exakt dasselbe.
    JOIN verbindet 2 Tabellen nebeneinander über definierte Felder, UNION verkleistert 2 Tabellen untereinander. Um zu der Anzahl der Schleusungen zu kommen, mußt Du in jedem Falle also erst einmal 2 Tabellen via JOIN verbinden, auch wenn Du die Syntax ohne JOIN verwendest.

    Wenn Du nun unbedingt noch UNION verwenden willst, dann mache einmal die Abfrage mit HAVING > 0 und einmal mit HAVING = 0:

    Code:
    test=*# select a.name, count(d.*) from schiff a left join durchfahrt d on a.id=d.schiff group by a.name having count(d.*) > 0 UNION select a.name, count(d.*) from schiff a left join durchfahrt d on a.id=d.schiff group by a.name having count(d.*) = 0;
       name   | count
    ----------+-------
     schiff 3 |     0
     schiff 1 |     2
     schiff 2 |     1
    (3 rows)
    
    Das ist natürlich auch Bullshit, weil es einfacher ginge, das Explain zeigt es:

    Code:
    test=*# explain select a.name, count(d.*) from schiff a left join durchfahrt d on a.id=d.schiff group by a.name having count(d.*) > 0 UNION select a.name, count(d.*) from schiff a left join durchfahrt d on a.id=d.schiff group by a.name having count(d.*) = 0;
                                            QUERY PLAN
    -------------------------------------------------------------------------------------------
     HashAggregate  (cost=240.10..244.10 rows=400 width=64)
       ->  Append  (cost=114.55..238.10 rows=400 width=64)
             ->  HashAggregate  (cost=114.55..117.05 rows=200 width=64)
                   Filter: (count(d.*) > 0)
                   ->  Hash Right Join  (cost=37.68..98.50 rows=2140 width=64)
                         Hash Cond: (d.schiff = a.id)
                         ->  Seq Scan on durchfahrt d  (cost=0.00..31.40 rows=2140 width=36)
                         ->  Hash  (cost=22.30..22.30 rows=1230 width=36)
                               ->  Seq Scan on schiff a  (cost=0.00..22.30 rows=1230 width=36)
             ->  HashAggregate  (cost=114.55..117.05 rows=200 width=64)
                   Filter: (count(d.*) = 0)
                   ->  Hash Right Join  (cost=37.68..98.50 rows=2140 width=64)
                         Hash Cond: (d.schiff = a.id)
                         ->  Seq Scan on durchfahrt d  (cost=0.00..31.40 rows=2140 width=36)
                         ->  Hash  (cost=22.30..22.30 rows=1230 width=36)
                               ->  Seq Scan on schiff a  (cost=0.00..22.30 rows=1230 width=36)
    (16 rows)
    
    Meine erste Lösung:

    Code:
    test=*# explain select a.name, count(d.*) from schiff a left join durchfahrt d on a.id=d.schiff group by a.name ;
                                      QUERY PLAN
    -------------------------------------------------------------------------------
     HashAggregate  (cost=109.20..111.20 rows=200 width=64)
       ->  Hash Right Join  (cost=37.68..98.50 rows=2140 width=64)
             Hash Cond: (d.schiff = a.id)
             ->  Seq Scan on durchfahrt d  (cost=0.00..31.40 rows=2140 width=36)
             ->  Hash  (cost=22.30..22.30 rows=1230 width=36)
                   ->  Seq Scan on schiff a  (cost=0.00..22.30 rows=1230 width=36)
    (6 rows)
    
    Merke: man kann IMMER etwas komplizierter machen als notwendig. Muß man aber nicht.

    Andreas
     
Die Seite wird geladen...

Diese Seite empfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden