Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   SQL-Abfrage über n-m-Beziehung (https://www.delphipraxis.net/186638-sql-abfrage-ueber-n-m-beziehung.html)

e-gon 18. Sep 2015 11:53

Datenbank: Access • Version: 2003 • Zugriff über: TADOQuery

SQL-Abfrage über n-m-Beziehung
 
Hallo,

wahrscheinlich gibt es schon viele Einträge zu diesem Thema. Aber ich fand keinen. :oops:

Problembeschreibung:
Zwei Tabellen:

1. Tabelle: GERICHT

ID Gericht
--------------
0 Schnitzel
1 Forelle
2 Steak


2. Tabelle: BEILAGE

ID Beilage
-------------
0 Nudeln
1 Reis
2 Kartoffeln


Um die beiden Tabellen zu verknüpfen gibt es eine 3. Tabelle "GERICHT_BEILAGE" mit den beiden Schlüsseln GerichtID und BeilageID.

GerichtID BeilageID
-------------------
0 0
0 2
1 2
2 1
...

Wie finde ich jetzt per SQL-Abrage z. B. alle Gerichte, die Nudeln UND Kartoffeln als Beilage haben? Folgender Code gibt jedenfalls eine leere Datenmenge zurück:
Delphi-Quellcode:
SELECT GERICHT.Gericht, BEILAGE.ID
FROM BEILAGE INNER JOIN (GERICHT INNER JOIN GERICHT_BEILAGE ON GERICHT.ID = GERICHT_BEILAGE.GerichtID) ON BEILAGE.ID = GERICHT_BEILAGE.BeilageID
WHERE (BEILAGE.ID=0) And (BEILAGE.ID=2);
Kann mir jemand sagen wie das Problem heißt und nach was ich suchen muss oder hat jemand gerade eine Lösung dafür?

Gruß
e-gon

Sir Rufo 18. Sep 2015 12:08

AW: SQL-Abfrage über n-m-Beziehung
 
Du fragst ab, in welcher Zeile
SQL-Code:
(BEILAGE.ID=0) And (BEILAGE.ID=2)
.

Bislang kann ein Wert nur einen Wert haben, aber nicht zwei gleichzeitig :stupid:

DeddyH 18. Sep 2015 12:09

AW: SQL-Abfrage über n-m-Beziehung
 
Suchst Du vielleicht eher so etwas?
SQL-Code:
SELECT
  G.Gericht, B.ID
FROM
  Beilage B
INNER JOIN
  GERICHT_BEILAGE GB ON GB.BeilageID = B.ID
INNER JOIN
  Gericht G ON GB.GerichtID = G.ID
WHERE
  B.ID IN (0, 2)
Eine Beilage kann ja wahrscheinlich nicht gleichzeitig 2 verschiedene IDs haben.

p80286 18. Sep 2015 12:10

AW: SQL-Abfrage über n-m-Beziehung
 
SQL-Code:
select distinct GERICHT.Gericht
from GERICHT join GERICHT_BEILAGE GB1 on (GERICHT.ID=GB1.GerichtID)
             join BEILAGE B1 on (GB1.BeilageID=B1.ID and B1.Beilage='Kartoffeln')
             join GERICHT_BEILAGE GB2 on (GERICHT.ID=GB2.GerichtID)
             join BEILAGE B2 on (GB2.BeilageID=B1.ID and B2.Beilage='Reis')
so sollte es gehen.
Alternativ könnte man auch exists verwenden, aber das ist etwas langsamer, je nach verwendeter DB.

Gruß
K-H

P.S.
Spätestens wenn nach ein paar Monaten eine solche Abfrage nochmals angeschaut wird, fragt man sich "und was steckt hinter ID=2?"
Darum sollte man solche Verkürzungen meiden wann immer es geht, oder einen Kommentar dazu schreiben.

Sir Rufo 18. Sep 2015 12:15

AW: SQL-Abfrage über n-m-Beziehung
 
In groben Zügen:

Finde alle Gerichte, die entweder die Beilage1 oder Beilage2 haben und nimm nur die Gerichte, die zwei Treffer haben.

e-gon 18. Sep 2015 12:26

AW: SQL-Abfrage über n-m-Beziehung
 
Vielen Dank für die schnellen Antworten!

@DeddyH:
Der "IN"-Befehl ist doch auch wieder "OR" und nicht "AND", oder?

@p80286:
Exists ist aber vielleicht die einfachere Lösung, oder?

Gruß
e-gon

e-gon 18. Sep 2015 12:37

AW: SQL-Abfrage über n-m-Beziehung
 
Also so funktioniert es, ist aber wohl ziemlich langsam...

Code:
SELECT GERICHT.Gericht
FROM GERICHT
WHERE (EXISTS(SELECT GERICHT_BEILAGE.GerichtID, BEILAGE.ID FROM BEILAGE INNER JOIN GERICHT_BEILAGE ON BEILAGE.ID = GERICHT_BEILAGE.BeilageID WHERE (GERICHT_BEILAGE.GerichtID=GERICHT.ID) AND (BEILAGE.ID=0))=True)
AND
(EXISTS(SELECT GERICHT_BEILAGE.GerichtID, BEILAGE.ID FROM BEILAGE INNER JOIN GERICHT_BEILAGE ON BEILAGE.ID = GERICHT_BEILAGE.BeilageID WHERE (GERICHT_BEILAGE.GerichtID=GERICHT.ID) AND (BEILAGE.ID=2))=True);

p80286 18. Sep 2015 12:52

AW: SQL-Abfrage über n-m-Beziehung
 
Da hast Du etwas falsch verstanden
Bisher sind Dir verschieden Strategien vorgeschlagen worden wie Du an deine Daten kommen könntest.
Je nach betroffener Datenmenge ist es z.B. sinnvoll zuerst die Gerichte zu selektieren, die zwei (oder mehr?) Beilagen haben. Und diese dann auf 'Kartoffeln' und 'Reis' zu prüfen.
Alternativ wählst Du erst alle Gerichte mit Reis oder Kartoffeln als Beilage und schaust welche davon Reis und Kartoffeln haben. Da führen viel (Um)Wege nach Rom.
(Wenn Du meinen Vorschlag um die Beilage ergänzt bekommst Du eine wundersame Datenvermehrung)

Mit exists meinte ich so etwas z.B.

SQL-Code:

SQL-Code:
select distinct GERICHT.Gericht
from GERICHT join GERICHT_BEILAGE GB1 on (GERICHT.ID=GB1.GerichtID)
              join BEILAGE B1 on (GB1.BeilageID=B1.ID and B1.Beilage='Kartoffeln')
where exists (select * from GERICHT_BEILAGE GB join Beilage on (Beilage.ID=gb.BeilageID and Beilage.Beilage='Reis') where gb.gerichtID=GerichtID)
Du selektierst ein Gericht mit einer Beilage und prüfst ob es hierzu auch die zweite Beilage gibt.

Gruß
K-H

Jumpy 18. Sep 2015 13:20

AW: SQL-Abfrage über n-m-Beziehung
 
Mein Weg nach Rom, der auch mit mehr als 2 Beilagen funktionieren sollte:

SQL-Code:
Select GB.GerichtID From
  (Select * From GERICHT_BEILAGE
   Where BeilageID in ([Liste der BeilagenIDs])) GB
Group By GB.GerichtID
Having count(GB.GerichtID)=[Anzahl der Beilagen]
Die Gerichtsbezeichnung aus der Gerichtstabelle kann man sich dann ja noch dazu joinen...


Edit: Ich sehe gerade, dass das glaub ich komplitzierter ist als es sein muss, den inneren Subselect braucht man glaub ich gar nicht.

Dejan Vu 18. Sep 2015 22:42

AW: SQL-Abfrage über n-m-Beziehung
 
Code:
select *
  from GERICHT g
  where exists (
    select 1 from GERICHT_BEILAGE g1 where BeilageID=0 and g1.gerichtID=g.iD
    )
  and exists (   
    select 1 from GERICHT_BEILAGE g1 where BeilageID=2 and g1.gerichtID=g.iD
    )
oder sowas wie
Code:
select GerichtID
  from GERICHT_BEILAGE
 where BeilageID in (0,2)
 group By GerichtID
       having Count(distinct BeilageID)=2
Typische DWH Anforderung 'Käufer, die X kaufen, kauften auch ....'

Bei dynamischer Anforderung (d.h. Beilagen können in einem Filter per Multiselect ausgewählt werden), würde ich die 2. Variante wählen, wobei die 'IN' Klausel und das erwartete Count-Resultat durch die Selektion bestimmt wird.


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:33 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz