Delphi-PRAXiS
Seite 1 von 2  1 2   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Komplizierte SQL-Abfrage (https://www.delphipraxis.net/204886-komplizierte-sql-abfrage.html)

EmWieMichael 10. Jul 2020 08:36

Datenbank: SQL-Server • Version: alle • Zugriff über: Devart

Komplizierte SQL-Abfrage
 
Hallo SQL-Spezis!

Obwohl ich bereits seit einiger Zeit mit SQL arbeite, weiß ich für das nachfolgend beschriebene Problem nichteinmal ansatzweise eine Lösung.

Gegeben sind folgende Tabellen:
- PERSON
- EIGENSCHAFT
- AUFTRAG

Die Tabellen EIGENSCHAFT und AUFTRAG enthalten zu jedem Personensatz 0..n Sätze. Die logische Verbindung
wird über Nummernfelder realisiert: PERSON.NUM enthält einen einmaligen Integerwert, EIGENSCHAFT.PNUM und
AUFTRAG.PNUM erhalten PERSON.NUM und "zeigen" so auf den entsprechenden Personensatz.
Die Auftragstabelle enthält u. a. das Feld AUFTRAG.TYP (Integer) mit Werten zwischen 1 und 20.

So, nun zu meinem Problem:
Ich möchte sämtliche Personen selektieren, die
a) über mindestens eine Eigenschaft verfügen,
und (!)
b) entweder keine Auftragssätze besitzen,
oder (!)
eine beliebige Anzahl Auftragssätze besitzen, davon aber mindestens ein Satz, nicht vom Typ n ist.

Selbstredend ist es der b)-Teil der Abfrage, der meine Stirn in Falten legt. Lässt sich die
Abfrage überhaupt mit SQL realisieren?

Ich bin für jeden Tipp dankbar!

Michael


EDIT

Ein Beispiel:

PERSON
NUM NAME
10 Müller
11 Meyer
12 Schmidt
13 Schulze

EIGENSCHAFT
PNUM WERT
10 Musiker
10 Handballer
11 Tänzer
12 Angler
12 Segler

AUFTRAG
PNUM TYP
10 5
10 8
11 5
13 8
13 9

Setze ich z. B. als Ausschlusskriterium AUFTRAG.TYP = 5 (b-Teil der Abfrage) ein, muss die
Abfrage zu folgendem Ergebnis führen:

10 Müller (er hat mindestens eine Eigenschaft, und einen Auftragssatz <> Typ 5)
12 Schmidt (er hat mindestens eine Eigenschaft, und keinen Auftragssatz)

Nicht im Seklektionsergebnis:
Meyer hat zwar eine Eigenschaft, aber nur Aufrtagssatz vom Typ 5.
Schulze hat zwar einen Auftragssatz <> Typ 5, aber keine Eigenschaft.

Jasocul 10. Jul 2020 09:13

AW: Komplizierte SQL-Abfrage
 
Da du dich mit SQL auskennst, wie du schreibst, werfe ich hier mal nur "exists" in den Raum

KodeZwerg 10. Jul 2020 09:40

AW: Komplizierte SQL-Abfrage
 
Ich bin echt kein DB Mensch, lasse mir da lieber von "Fertigprodukten" helfen, aber kommt man da nicht besser mit einer "IFNULL()" abfrage voran?

//edit
ich vermute das ich eher "WHERE spalteXYZ IS NOT NULL" meinte...

Jumpy 10. Jul 2020 09:56

AW: Komplizierte SQL-Abfrage
 
Diese Bedingung:

Zitat:

eine beliebige Anzahl Auftragssätze besitzen, davon aber mindestens ein Satz, nicht vom Typ n ist.
würde ich umformulieren in:

Zitat:

die mindestens einen Auftragssatz besitzen, der nicht Typ n ist.
Dann sieht man die Lösung leichter: Einfach beide Tabellen per Left Join zur Personen-Tabelle joinen, mit entsprechenden Where-Bedingungen.

dataspider 10. Jul 2020 10:02

AW: Komplizierte SQL-Abfrage
 
So als Prinzip:

SQL-Code:

select * from person p where
    exists(select * from eigenschaft e where e.pnum = p.enum)
    and
    (
      not exists(select * from auftrag a where a.pnum = p.enum)
        or
        (
           exists(select * from auftrag a1 where a1.pnum = p.enum) and
           exists(select * from auftrag a2 where a2.pnum = p.enum and a2.typ <> 5)
        )
    )
Frank

TigerLilly 10. Jul 2020 10:06

AW: Komplizierte SQL-Abfrage
 
Ich möchte sämtliche Personen selektieren, die
select * from Person p where (

a) über mindestens eine Eigenschaft verfügen,
1<=(select Count(*) from eigenschaft e where e.pid=p.id)
und (!)
and (
b) entweder keine Auftragssätze besitzen,
0=(select Count(*) from auftrag a where a.pid=p.id)
oder (!)
or
eine beliebige Anzahl Auftragssätze besitzen, davon aber mindestens ein Satz, nicht vom Typ n ist.
1<=(select Count(*) from auftrag a where a.pid=p.id and typ <> n)
))


Wobei hier "beliebige Anzahl" als "mind.1" verstanden wird.

Jasocul 10. Jul 2020 10:47

AW: Komplizierte SQL-Abfrage
 
@TigerLilly:
Deine Variante dürfte auch funktionieren, ist aber deutlich langsamer als eine Lösung mit exists.

Exists hört auf zu arbeiten, sobald ein Datensatz getroffen wurde. Ein Count muss ja trotzdem ermitteln, wie viele Treffer es gibt.

TigerLilly 10. Jul 2020 10:54

AW: Komplizierte SQL-Abfrage
 
Ja, das ist grundsätzlich richtig. Ich wollte nur eine pädagogische Lösung nahe an der Fragestellung, von der aus man weiter optimieren kann.

EmWieMichael 10. Jul 2020 11:11

AW: Komplizierte SQL-Abfrage
 
Hui, seid Ihr flott :).
Das Exists-Statement scheint ja der richtige Ansatz zu sein. Leider schaffe ich es heute nicht mehr, die gezeigten Varianten zu testen. Montag geht es weiter...

Herzlichen Dank für Eure Hilfe! :thumb:

Rainbow6 10. Jul 2020 21:10

AW: Komplizierte SQL-Abfrage
 
Es empfiehlt sich immer so eine Abfrage mit WITH aufzubauen - also z.B.:

Code:
WITH
PersonenOhneAuftrag AS (
   SELECT pnum FROM Auftrag GROUP BY pnum HAVING COUNT(*) = 0
),
PersonenOhneNAuftrag AS (
   SELECT pnum FROM Auftrag WHERE Typ <> N GROUP BY pnum
),
...
SELECT * FROM Person
WHERE num NOT IN (SELECT pnum FROM PersonenOhneAuftrag)
OR num IN (SELECT pnum FROM PersonenOhneNAuftrag)
...
Durch das WITH hast du die Möglichkeit, deine Abfragen Stück für Stück zu testen und zu strukturieren - und die meisten Query Optimizer haben es damit auch leichter - zumindest ist das bei DB2 so.

Grüße
Daniel


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:51 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