Hallo,
SELECT ID FROM tab WHERE
ID IN (SELECT ID FROM tab WHERE Modus='h')
AND (
ID-1 NOT IN (SELECT ID FROM tab WHERE Modus='h')
OR
ID+1 NOT IN (SELECT ID FROM tab WHERE Modus='h')
)
> So - und nun hab ich keine Idee mehr, wie ich weiter machen soll/muss, um dahin zu kommen wo ich hin will. Oder geht das vielleicht gar nicht in einer Abfrage?
das geht schon - aber schön oder gar effizient ist [anders](https://forum.selfhtml.org/?t=209167&m=1423210) ...
1\. Um zwischen Beginn und Ende eines Modus zu unterscheiden, selektieren wir immer nur den entsprechenden Abschnitt:
~~~sql
SELECT
ID,
'h' modus,
'beginn' typ
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='h')
AND
ID-1 NOT IN (SELECT ID FROM tab WHERE Modus='h')
UNION ALL
SELECT
ID,
'h',
'ende'
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='h')
AND
ID+1 NOT IN (SELECT ID FROM tab WHERE Modus='h')
2. Du siehst, dass Du für jeden Modus-Wert eine solche UNION dranhängen musst:
SELECT
ID,
'h' modus,
'beginn' typ
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='h')
AND
ID-1 NOT IN (SELECT ID FROM tab WHERE Modus='h')
UNION ALL
SELECT
ID,
'h',
'ende'
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='h')
AND
ID+1 NOT IN (SELECT ID FROM tab WHERE Modus='h')
UNION ALL
SELECT
ID,
'k',
'beginn'
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='k')
AND
ID-1 NOT IN (SELECT ID FROM tab WHERE Modus='k')
UNION ALL
SELECT
ID,
'k',
'ende'
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='k')
AND
ID+1 NOT IN (SELECT ID FROM tab WHERE Modus='k')
ORDER BY
ID
liefert Dir:
ID | modus | typ
-------------------
2 | k | beginn
4 | k | ende
6 | h | beginn
8 | h | ende
10 | h | beginn
12 | h | ende
Mit dieser Tabelle (als tab2) erhältst Du mit folgender korrelierten Unterabfrage
SELECT
i1.modus,
i1.ID vonID,
(SELECT MIN(i2.ID) FROM tab2 i2 WHERE i2.ID > i1.ID) bisID
FROM
tab2 i1
WHERE
i1.typ = 'beginn'
ORDER BY
i1.ID
das von Dir gewünschte Ergebnis:
modus | vonID | bisID
---------------------
k | 2 | 4
h | 6 | 8
h | 10 | 12
Dabei nutzen wir aus, dass sich Beginn und Ende stets abwechseln. Wir suchen daher die kleinste ID, die größer ist als unser aktueller Beginn.
Nun kannst Du noch das wüste UNION-Konstrukt anstelle von tab2 (gleich zweimal!) einbauen und Du hast *eine* Abfrage, die Dir das gewünschte Ergebnis liefert:
SELECT
grenzen.modus,
grenzen.ID vonID,
(
SELECT
MIN(g2.ID)
FROM (
SELECT
i1.ID,
'h' modus,
'beginn' typ
FROM
tab i1
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='h')
AND
ID-1 NOT IN (SELECT ID FROM tab WHERE Modus='h')
UNION ALL
SELECT
ID,
'h',
'ende'
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='h')
AND
ID+1 NOT IN (SELECT ID FROM tab WHERE Modus='h')
UNION ALL
SELECT
ID,
'k' modus,
'beginn' typ
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='k')
AND
ID-1 NOT IN (SELECT ID FROM tab WHERE Modus='k')
UNION ALL
SELECT
ID,
'k',
'ende'
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='k')
AND
ID+1 NOT IN (SELECT ID FROM tab WHERE Modus='k')
) AS g2
WHERE
g2.ID > grenzen.ID) bisID
FROM (
SELECT
i1.ID,
'h' modus,
'beginn' typ
FROM
tab i1
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='h')
AND
ID-1 NOT IN (SELECT ID FROM tab WHERE Modus='h')
UNION ALL
SELECT
ID,
'h',
'ende'
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='h')
AND
ID+1 NOT IN (SELECT ID FROM tab WHERE Modus='h')
UNION ALL
SELECT
ID,
'k' modus,
'beginn' typ
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='k')
AND
ID-1 NOT IN (SELECT ID FROM tab WHERE Modus='k')
UNION ALL
SELECT
ID,
'k',
'ende'
FROM
tab
WHERE
ID IN (SELECT ID FROM tab WHERE Modus='k')
AND
ID+1 NOT IN (SELECT ID FROM tab WHERE Modus='k')
) AS grenzen
WHERE
grenzen.typ = 'beginn'
ORDER BY
grenzen.ID
Wenn Du die unterschiedlichen Modi zusätzlich ermitteln musst, wird's noch lustiger. Spätestens dann möchtest Du eine Stored Procedure schreiben, die ein einziges Mal durch die Ausgangstabelle (sortiert) iteriert und das Ergebnis zusammenstellt ...
Freundliche Grüße
Vinzenz