Seite 1 von 1

select between mit subquery

Verfasst: Mo, 02. Aug 2021 22:57
von Werner_Bayern
Frage an die SQL-Profis,

gegeben ist eine Tabelle mit Wertebereiche:

id_von, id_bis, Name
1, 1000, Kevin
1001, 2000, Pascal
2001, 3000, Elli
2999, 4000, Falsch

Gesucht sind alle Sätze, deren Wertebereich überlappend ist, also hier der letzte Satz.

Bekomme es mit einem

Code: Alles auswählen

select * from blabla where id_von between (select id_von from blabla) and (select id_bis from blabla) and id_bis between ...
nicht hin:
als Ausdruck verwendete Unteranfrage ergab mehr als eine Zeile
Was auch nachvollziehbar ist.

Wie löse ich das? Mit IN?

Re: select between mit subquery

Verfasst: Di, 03. Aug 2021 8:32
von Marcus Herz
Mir ist die Aufgabenstellung nicht klar. Weleche Überlappung?

Re: select between mit subquery

Verfasst: Di, 03. Aug 2021 8:49
von HaPe
Überlappung
Überlappung
ueberlappung.jpg (36.69 KiB) 4626 mal betrachtet

Re: select between mit subquery

Verfasst: Di, 03. Aug 2021 9:05
von Marcus Herz
Nicht genau gelesen!
Das ist wie mit der Terminierung von Aufträgen, welche überlappen sich nach einer Verschiebung:
- zeige alle Sätze, deren Max größer als das Minimum des nächsten Wertebreiches ist
- zeige alle Sätze, deren Minimum kleiner als das Maximum der kleineren Wertebreiche ist

Code: Alles auswählen

select * from 
(select name, min(id_von) as minvon, max(id_bis) as maxbis
from blabla
group by name) grpblabla
where maxbis > (select min(id_von) from balbla where  max(id_bis) > grpblabla.minvon)  /* alle späteren */
or minvon < (select max(id_bis) from balbla where  min(id_von) < grpblabla.maxbis)  /* alle früheren */
Habe mir keine Tabelle gemacht, um das zu testen.

Re: select between mit subquery

Verfasst: Di, 03. Aug 2021 9:08
von Marcus Herz
Das Ergebnis sollen 2 Sätze sein,
Elli und Falsch
weil es ja (noch) kein Kriterium gibt, wer eine Regel verletzt,

Re: select between mit subquery

Verfasst: Di, 03. Aug 2021 10:15
von nightcrawler

Code: Alles auswählen

create table blabla(id_von integer, id_bis integer, name cichar(30));
insert into blabla(id_von, id_bis, name) values
(1, 1000, 'Kevin'),
(1001, 2000, 'Pascal'),
(2001, 3000, 'Elli'),
(2999, 4000, 'Falsch');
Ich gehe so vor:
1. die Tabelle mit sich selber kreuzen (INNER JOIN) auf alle Datensätze, bei denen b.von<a.bis:

Code: Alles auswählen

select a.*, b.* from blabla b
inner join blabla a on b.id_von<a.id_bis
2. Das Ergebnis weiter einschränken auf alle Datensätze, bei welchen b.bis>a.bis

Code: Alles auswählen

select a.*, b.* from blabla b
inner join blabla a on b.id_von<a.id_bis
and b.id_bis>a.id_bis
3. Evtl noch die Datensätze wegnehmen, bei denen a und b denselben anzeigen (bei <> nicht notwendigt, aber falls >= oder <= verwendet werden)

Code: Alles auswählen

select a.*, b.* from blabla b
inner join blabla a on b.id_von<a.id_bis
and b.id_bis>a.id_bis
and b.rowid<>a.rowid
Das Ergebnis ist dann erst der richtige Datensatz und darauf folgend der, der die Überschneidung begeht:
2001 3000 Elli 2999 4000 Falsch

Re: select between mit subquery

Verfasst: Di, 03. Aug 2021 22:04
von Werner_Bayern
Servus Marcus,

vielen Dank, da wäre ich nicht drauf gekommen. Leider schmeisst PG mir da den Fehler:
Aggregatfunktionen sind in WHERE nicht erlaubt
(select min(id_von) from blabla where max(id_bis...
und verweist auf das max(id_bis

Re: select between mit subquery

Verfasst: Di, 03. Aug 2021 22:09
von Werner_Bayern
Servus Joachim,

danke, das funktioniert, wenn ich die rowid weglasse, die kennt PG ja nicht. Aber da hab ich meinen Primärschlüssel, den ich dafür verwenden kann. =D>

Re: select between mit subquery

Verfasst: Di, 03. Aug 2021 22:20
von Werner_Bayern
Hatte mir zwischenzeitlich so geholfen:

Code: Alles auswählen

      oTicket:select("name, id_von, id_bis from " + SQL_TICKET_TABLES[3] + " where tabelle = '" + SQL_TICKET_TABLES[i] + "' order by id_von", "temp")
      do while .not. eof()
         nSatznr := recno()
         nID_von := temp->id_von
         nID_bis := temp->id_bis
         cName := temp->name
         dbSkip()
         do while .not. eof()
            if (nID_von >= temp->id_von .and. nID_von <= temp->id_bis) .or. (nID_bis >= temp->id_von .and. nID_bis <= temp->id_bis)
               aadd(aDoppelt, {cName, temp->name, nID_von, nID_bis, temp->id_von, temp->id_bis, SQL_TICKET_TABLES[i]})
            endif
            dbskip()
         enddo
         dbGoto(nSatznr)
         dbSkip()
      enddo
Muss das inner join wohl nur noch um die 2. Bedingung ergänzen, dann werden aus 16 Zeilen herkömmlichen Codes eine SQL-Anweisung! Toll!