Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi "Bedingte" Abfrage über mehrere Tabellen (https://www.delphipraxis.net/112438-bedingte-abfrage-ueber-mehrere-tabellen.html)

Tyrael Y. 21. Apr 2008 13:49

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

"Bedingte" Abfrage über mehrere Tabellen
 
Hallo zusammen,

ich habe 5 Tabellen.

In TabelleA und TabelleB sind Informationen die für jeden Datensatz wichtig sind.
In TabelleB gibt es ein Feld Typ, was eine Zahl ist.

Je nachdem welcher Typ in TabelleB angegeben ist, bräuchte ich nun die zusätzlichen Daten
aus TabelleC, TabelleD oder TabelleE.

Muss ich jetzt drei verschiedene Abfragen machen oder ist es möglich dies über eine
Abfrage zu ermöglichen?

Bernhard Geyer 21. Apr 2008 13:59

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Wird vermutlich mit Joins + Union gehen

SQL-Code:
select ...
from maintab inner join tabellea on ...
union
select ...
from maintab inner join tabelleb on ...

Tyrael Y. 21. Apr 2008 14:06

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Union?

Das vereinigt doch einfach nur zwei Tabellen, so daß Einträge, die in beiden Tabellen vorkommen eliminiert werden, oder habe ich da was missverstanden?


Also nochmal...ich möchte bedingt vom Wert eines Feldes aus einer bestimmten Tabelle, Daten aus einer von mehreren Tabellen zu den Datensätzen "joinen", wenns geht natürlich.

Bernhard Geyer 21. Apr 2008 14:17

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Zitat:

Zitat von Tyrael Y.
Also nochmal...ich möchte bedingt vom Wert eines Feldes aus einer bestimmten Tabelle, Daten aus einer von mehreren Tabellen zu den Datensätzen "joinen", wenns geht natürlich.

keine verbietet dir in der Where-Bedigung oder im Join selbst dies Wert abzuchecken.

SQL-Code:
select ...
from maintab inner join tabellea on (maintab.id = tabellea.id)
where maintab.feldxyz = <bestimmterwert>
union
select ...
from maintab inner join tabellea on (maintab.id = tabelleb.id)
where maintab.feldxyz = <bestimmter_anderer_wert>

Tyrael Y. 21. Apr 2008 14:22

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Aaah verstehe jetzt....danke....werde es mal testen.

Besten Dank.

Tyrael Y. 23. Apr 2008 08:17

Re: "Bedingte" Abfrage über mehrere Tabellen
 
da ich parallel an mehreren Sachen arbeite, kam ich bisher nicht dazu den Vorschlag zu testen. Heute morgen habe ich testweise Tabellen angelegt und probiere direkt auf der Datenbank Abfragen aus, irgendwie komme ich leider nicht zu meinem gewünschtem Ergebnis.

Vielleicht kann mir einer bissel behilflich sein.

Ich habe beispielhaft folgende Tabellen

Code:
MainTabelle   TabelleAllgemein  TabelleTyp1   TabelleTyp2  TabelleTyp3
ID            ID                ID           ID          ID
Text          Typ               Größe        Farbe       Wert
               Anzahl            Gewicht      Leistung
Die Felder sind nur beispielhaft und entsprechen nicht meinem Projekt.
Ich möchte damit nur zeigen, daß die "Typ"-Tabellen unterschiedlich sind.

ID ist der Primärschlüssel und ist in allen Tabellen identisch.

In jedem Ergebnis erwarte ich die Daten aus MainTabelle, TabelleAllgemein und aus
einem der "Typ"-Tabellen, wobei das Ergebnis nur die Daten enthalten sollte, die dem Wert aus dem Feld Typ aus TabelleAllgemein entsprechen.

Beispiel, wenn ich folgende Daten habe...

Code:
MainTabelle:  TabelleAllgemein:  TabelleTyp1:       TabelleTyp2:         TabelleTyp3:
ID  Text     ID  Typ  Anzahl  ID Größe Gewicht  ID Farbe Leistung  ID Wert
23   Haus     23   1     2        23  45    1000      35  Grün  1          80  50 
35   Garten   35   2     1        56  20    100       78  Gelb  50000
56   Auto     56   1     5        83  11    3000
78   Sonne    78   2     1
80   Mensch   80   3     0
83   Gebäude  83   1     12
Wenn ich in meiner Abfrage nun als Typ eine der möglichen Typen eingebe erwarte ich folgende Ergebnisse.

Code:
<Bei Typ = 1>
ID = 23, Text = Haus  , Typ = 1, Anzahl = 2 , Größe = 45, Gewicht = 1000
ID = 56, Text = Auto  , Typ = 1, Anzahl = 5 , Größe = 20, Gewicht = 100
ID = 83, Text = Gebäude, Typ = 1, Anzahl = 12, Größe = 11, Gewicht = 3000

<Bei Typ = 2>
ID = 35, Text = Garten, Typ = 2, Farbe = Grün , Leistung = 1
ID = 78, Text = Sonne , Typ = 2, Farbe = Gelb , Leistung = 50000

<Bei Typ = 3>
ID = 80, Text = Mensch, Typ = 3, Wert = 50
Wie kann ich aus den oben befindlichen Tabellen, die darunter stehenden Ergebnisse erzeugen, bei Angabe des Typen in der Abfrage?

Vielen Dank fürs Lesen und Helfen.

alzaimar 23. Apr 2008 08:59

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Wie willst Du drei unterschiedliche Tabellenstrukturen in einer(!) Tabelle darstellen?

Erstelle Dir also eine homogene Tabellenstruktur, die alle Datenaufnehmen kann und fülle dann die einzelnen Spalten, indem Du -wie Bernhard schon mittels UNION gezeigt hat- bei den einzelnen Untertabellen die ungültigen Spalten mit NULL auffüllst.

NormanNG 23. Apr 2008 09:07

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Hi,

evtl. genügt schon ein einfacher left join?
SQL-Code:
select *
from maintable mt
left join tabelletyp1 t1 on t1.id = mt.id
left join tabelletyp2 t2 on t2.id = mt.id
:
Es werden immer alle Spalten angezeigt, wo keine Daten vorliegen, kommt NULL
(bei MSSQL jedenfalls).

Tyrael Y. 23. Apr 2008 09:20

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Das Problem bei UNION ist das die Struktur der einzelnen SELECT-Anweisungen identisch sein müssen.

Code:
...
LEFT JOIN TabelleTyp1 ON MainTabelle.ID = TabelleTyp1.ID AND TabelleAllgemein.Typ = 1
...
LEFT JOIN TabelleTyp2 ON MainTabelle.ID = TabelleTyp1.ID AND TabelleAllgemein.Typ = 2
..
LEFT JOIN TabelleTyp3 ON MainTabelle.ID = TabelleTyp1.ID AND TabelleAllgemein.Typ = 3

...also das oben funktioniert nicht, aber sowas ähnliches habe ich mir vorgestellt wäre vielleicht möglich, so daß man unter bestimmten Voraussetzungen eine Tabelle "joint" und andere nicht mit einbezieht.

alzaimar 23. Apr 2008 09:24

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Zitat:

Zitat von Tyrael Y.
Das Problem bei UNION ist das die Struktur der einzelnen SELECT-Anweisungen identisch sein müssen.

Zitat:

Zitat von alzaimar
Wie willst Du drei unterschiedliche Tabellenstrukturen in einer(!) Tabelle darstellen?

Erstelle Dir also eine homogene Tabellenstruktur, die alle Datenaufnehmen kann und fülle dann die einzelnen Spalten, indem Du -wie Bernhard schon mittels UNION gezeigt hat- bei den einzelnen Untertabellen die ungültigen Spalten mit NULL auffüllst.

:wall:

Tyrael Y. 23. Apr 2008 09:36

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Reg dich nicht auf alzaimer,

ich danke dir, ich habe verstanden was Bernhard und du geschrieben hast.
Ich versuche halt gerade krampfhaft an eine Lösung zu gelangen, damit ich die Normalisierung, die durch diese Tabellenstruktur erschaffen wurde nicht wieder zunichte mache.

Ja du hast natürlich Recht, wenn du jetzt schreibst, daß Normalisierung nicht ein Gesetz ist, daß unbedingt erfüllt werden müsste.

Ich könnte natürlich auch hingehen, die Daten aus der MainTabelle und der AllgemeinenTabelle in einer SELECT-Anweisung holen, diese in eine Liste einfügen.
Danach diese Liste durchgehen und je nach Typ eine SELECT-Anweisung ausführen und die erhaltenen Daten in meine Liste hinzufügen. Dies würde heißen ich müsste sehr viele Anfragen an die Datenbank stellen.

Es gibt auf jeden Fall Wege, wie ich die Tabellen so belassen kann und trotzdem die gewünschten Daten bekomme.

Die Frage ist und bleibt, ob es wirklich keine mögliche SQL Anweisung gibt, die diese Arbeit in einem Zuge macht. Leider kann Access, soweit ich weiss, keine Stored Procedures, sonst könnte ich auch IF-Anweisungen einbauen und verschiedene Fälle kreieren.

Vielleicht gibt es ja doch einen eleganten Weg.

Fragen kostet nix, aufregen verkürzt das Leben. ;)


edit:
OK, ich habe eine Entscheidung getroffen.
Ich werde mehrere SELECT-Anweisungen machen, die jeweils für einen Typen stimmen.
Im Delphi-Code werde ich die verschiedenen Typen durchgehen und die entsprechenden SQL-Anweisungen ausführen.

Für das oben aufgeführte Beispiel würde es bedeuten, daß ich folgende Anweisungen bräuchte.

Code:
SELECT * FROM MainTabelle
LEFT JOIN TabelleAllgemein ON MainTabelle.ID = TabelleAllgemein.ID
LEFT JOIN TabelleTyp1 ON MainTabelle.ID = TabelleTyp1.ID
WHERE TabelleAllgemein.ID = 1


SELECT * FROM MainTabelle
LEFT JOIN TabelleAllgemein ON MainTabelle.ID = TabelleAllgemein.ID
LEFT JOIN TabelleTyp2 ON MainTabelle.ID = TabelleTyp2.ID
WHERE TabelleAllgemein.ID = 2


SELECT * FROM MainTabelle
LEFT JOIN TabelleAllgemein ON MainTabelle.ID = TabelleAllgemein.ID
LEFT JOIN TabelleTyp3 ON MainTabelle.ID = TabelleTyp3.ID
WHERE TabelleAllgemein.ID = 3
Ich habe es noch nicht gestestet, aber das sollte theoretisch funktionieren.

NormanNG 23. Apr 2008 09:58

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Hi,

statt
SQL-Code:
WHERE TabelleAllgemein.ID = 3
meinst du wohl

SQL-Code:
WHERE TabelleAllgemein.TYP = 3

alzaimar 23. Apr 2008 10:04

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Ich rege mich nicht auf, nur ist die Frage komisch, weil die Antwort schon längst fest steht.

Also:
SQL-Code:
Select    m.Id as [ID],
   m.Text as [Text],
   ta.Typ as [Typ],
   ta.Anzahl as [Anzahl],
   t1.[Größe],
   t1.[Gewicht],
   cast (NULL as VarChar (80)) as [Farbel],
   cast (NULL as int) as [Leistung],
   cast (NULL as money) as [Wert]
from   MainTabelle m
   join TabelleAllgemein ta on m.ID = ta.ID
   join TabelleType1 t1 on t1.ID = m.ID
where ta.Typ = 1
union
Select    m.Id as [ID],
   m.Text as [Text],
   ta.Typ as [Typ],
   NULL as [Anzahl],
   NULL as [Größe],
   NULL as [Gewicht],
   t2.Farbe,
   t2.Leistung,
   NULL as [Wert]
from   MainTabelle m
   join TabelleAllgemein ta on m.ID = ta.ID
   join TabelleType2 t2 on t1.ID = m.ID
where ta.Typ = 2
union
Select    m.Id as [ID],
   m.Text as [Text],
   ta.Typ as [Typ],
   NULL as [Anzahl],
   NULL as [Größe],
   NULL as [Gewicht],
   NULL as [Farbe],
   NULL as [Leistung],
   t3.Wert
from   MainTabelle m
   join TabelleAllgemein ta on m.ID = ta.ID
   join TabelleType2 t2 on t1.ID = m.ID
where ta.Typ = 3
Wenn Du das dynamisch haben willst, dann benötigst Du eine Pivot/Crosstabelle.

mkinzler 23. Apr 2008 10:06

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Zitat:

Ich rege mich nicht auf, nur ist die Frage komisch, weil die Antwort schon längst fest steht.
Du müsstest doch i.d.Z. wissen, das der neue Programmierertyp keinen Bock hat sich mit Grundlagen zu befassen, sich gedanklich in das Problem zu vertiefe, oder gesagtes an sein Problem anzupassen, er erwartet dass du ihm die Lösung fix und fertig lieferst.

Jelly 23. Apr 2008 10:11

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Zitat:

Zitat von Tyrael Y.
Code:
SELECT * FROM MainTabelle
LEFT JOIN TabelleAllgemein ON MainTabelle.ID = TabelleAllgemein.ID
LEFT JOIN TabelleTyp1 ON MainTabelle.ID = TabelleTyp1.ID
WHERE TabelleAllgemein.ID = 1


SELECT * FROM MainTabelle
LEFT JOIN TabelleAllgemein ON MainTabelle.ID = TabelleAllgemein.ID
LEFT JOIN TabelleTyp2 ON MainTabelle.ID = TabelleTyp2.ID
WHERE TabelleAllgemein.ID = 2


SELECT * FROM MainTabelle
LEFT JOIN TabelleAllgemein ON MainTabelle.ID = TabelleAllgemein.ID
LEFT JOIN TabelleTyp3 ON MainTabelle.ID = TabelleTyp3.ID
WHERE TabelleAllgemein.ID = 3

Damit hast du doch alles. Geliefert werden aber nur Spalten aus deiner MainTabelle. Den Join auf TabelleTyp3 kannst du dir also sparen.

Und du joins die ID aus Maintabelle mit der ID aus TabelleAllgemein. Da frag ich mich erstmal, wie sieht denn dein PK in TabelleAllgemein aus? Und falls es eine 1:1 Beziehung darstellen soll (sprich ID ist auch PK in Tabelleallgemein), warum machst du denn überhaupt 2 Tabellen, und legst nicht einfach alle Spalten in eine.

Da TabelleTyp1-3 unterschiedlicher Struktur sind, macht ein Gesamtergebnis in einem Select in meinen Augen überhaupt keinen Sinn. Du vergleichst Äpfel mit Birnen, und versuchst beides in einen Korb zu schmeissen.

Zu deiner Normalisierung: Du entscheidest über Typ in deiner TabelleAllgemein, welche TypTabelle als Referenztabelle gewählt werden soll. Ich würds andersrum machen. Ich würde in jeder TypTabelle eine Referenz auf TabelleAllgemein setzen (also gerade umgekehrt). Somit kann dir nicht passieren, dass wenn einer die Typ Id in TabelleAllgemein ändert, du plötzlich auf eine andere Tabelle referenzierst. Das ist eine Riesengefahrenquelle, und die Homogenität deiner Daten ist nicht mehr gewährleistet.

Tyrael Y. 23. Apr 2008 10:50

Re: "Bedingte" Abfrage über mehrere Tabellen
 
Zitat:

Zitat von NormanNG
Hi,
statt
...
meinst du wohl
SQL-Code:
WHERE TabelleAllgemein.TYP = 3

Ja natürlich. War ein Schreibfehler.


Zitat:

Zitat von alzaimar
Ich rege mich nicht auf, nur ist die Frage komisch, weil die Antwort schon längst fest steht.

Naja, wie ich oben erwähnt habe, gäbe es ja verschiedene Wege zu meinen Ergebnissen zu kommen.
Vielen Dank für die SQL-Anweisung. Zwei Fragen bitte noch dazu.

1. Du hast es in zwei verschiedenen Formen geschrieben
Code:
cast (NULL as VarChar (80)) as [Farbel]
...
NULL as [Farbe]
hat das eine bestimmte Bewandnis, vielleicht, daß man beim ersten mal erwähnen des Feldes den Typ und die Größe angeben muss?

2. Ich verstehe es doch richtig das durch zB.
Code:
NULL as [Farbe]
diese Feld "virtuell" zu dieser Tabelle hinzugefügt wird, oder?

Vielen Dank nochmal, sieht auf den ersten Blick, sehr vielversprechend aus.


Zitat:

Zitat von mkinzler
Du müsstest doch i.d.Z. wissen, das der neue Programmierertyp keinen Bock hat sich mit Grundlagen zu befassen, sich gedanklich in das Problem zu vertiefe, oder gesagtes an sein Problem anzupassen, er erwartet dass du ihm die Lösung fix und fertig lieferst.

Genau dessalb habe ich ja auch die erste Lösung, die auch funktionieren würde, direkt einprogrammiert und mich nicht damit auseinandergesetzt, ob es keine eleganter Lösung gibt. Danke für deinen nicht passenden Post.


Zitat:

Zitat von Jelly
Damit hast du doch alles. Geliefert werden aber nur Spalten aus deiner MainTabelle. Den Join auf TabelleTyp3 kannst du dir also sparen.

Ich dachte auch zuerst, daß ich alle Felder die ich haben möchte einzeln angeben müsste, aber ein
Code:
SELECT * FROM....LEFT JOIN....
hat dazu geführt, daß ich alle Felder aus allen Tabellen erhalten habe.
Vielleicht Access spezifisch?

Zitat:

Zitat von Jelly
Und du joins die ID aus Maintabelle mit der ID aus TabelleAllgemein. Da frag ich mich erstmal, wie sieht denn dein PK in TabelleAllgemein aus? Und falls es eine 1:1 Beziehung darstellen soll (sprich ID ist auch PK in Tabelleallgemein), warum machst du denn überhaupt 2 Tabellen, und legst nicht einfach alle Spalten in eine.

Ja es ist eine 1:1 Beziehung zwischen den beiden Tabellen.
Die Tabellen werden nicht nur von mir benutzt. Es gibt Fälle bei denen man nur die
Daten aus TabelleAllgemein braucht.

Zitat:

Zitat von Jelly
Da TabelleTyp1-3 unterschiedlicher Struktur sind, macht ein Gesamtergebnis in einem Select in meinen Augen überhaupt keinen Sinn. Du vergleichst Äpfel mit Birnen, und versuchst beides in einen Korb zu schmeissen.

Ich möchte halt alle Daten möglichst effizient holen.
Bei der Behandlung im Delphi Code erzeuge ich je nach Typ eine Objekt aus einer passenden Klasse.
Die Klassen haben einen gemeinsamen Vorfahren. Mein Korb ist die Objektliste und es ist nicht schlimm,
dort verschieden Typen (Äpfel, Birnen) zu haben, da ich es ein "Obstkorb" (der Vorfahr wäre Obst) reintue.
Ich brauche sie halt im Programm zur späteren Behandlung.

Zitat:

Zitat von Jelly
Zu deiner Normalisierung: Du entscheidest über Typ in deiner TabelleAllgemein, welche TypTabelle als Referenztabelle gewählt werden soll. Ich würds andersrum machen. Ich würde in jeder TypTabelle eine Referenz auf TabelleAllgemein setzen (also gerade umgekehrt). Somit kann dir nicht passieren, dass wenn einer die Typ Id in TabelleAllgemein ändert, du plötzlich auf eine andere Tabelle referenzierst. Das ist eine Riesengefahrenquelle, und die Homogenität deiner Daten ist nicht mehr gewährleistet.

Im Grunde hast du Recht, ich könnte es umbauen und es wäre auch richtig so.
Der Typ kann sich aber nie ändern. Ein Datensatz der angelegt wurde behält immer seinen Typen.
Er kann gelöscht werden, aber nie seinen Typen ändern.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:54 Uhr.

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