SQL: Ansteigende Zahlenfolgen ermitteln

Aus DBWiki
Wechseln zu: Navigation, Suche

Zurück zur Übersicht



Anders als unter Sequentiell ansteigende Zahlenfolgen ermitteln sei hier die Größe des Anstiegs variabel. Als Ausgangsbasis für dieses Beispiel verwenden wir wieder die Daten aus Aufeinanderfolgende Bereiche in einer Sequenz erkennen.

Allgemeine Lösung

Die Lösung ist ähnlich wie in Sequentiell ansteigende Zahlenfolgen ermitteln, wird aber dadurch komplexer, dass man jetzt keinen monotonen Anstieg des Werts von 1 hat und damit die Lösung über die Differenz zwischen Wert und id entfällt. In der NOT EXISTS-Klausel wird deshalb eine weitere Instanz der Ausgangstabelle benötigt (p3 und p4), um die Werte vergleichen zu können. Die triviale Anfangsbedingung p1.id < p2.id bleibt gleich. Für jedes Element zwischen p1 und p2 werden p3 und sein Vorgänger verglichen, um zu sehen, ob ihre Werte steigen. Die BETWEEN-Klausel reduziert den Umfang auf die Zeilen zwischen den Grenzen von p1 und p2 des jeweiligen Durchlaufs. Die p1-Grenze wird um 1 erhöht, womit alle Paare innerhalb des Bereichs abdeckt werden. Dabei ist zu beachten, dass immer ein Paar weniger als die Zahl der Zeilen zu vergleichen ist. Die letzten beiden Bedingungen in der WHERE-Klausel stellen analog zum Beispiel Sequentiell ansteigende Zahlenfolgen ermitteln sicher, dass die Grenzen des Durchlaufs nicht überschritten werden. Trifft eine der beiden letzten Bedingungen zu, wird der Durchlauf abgelehnt, weil es größere Werte gibt (uns interessieren ja nur die äußeren Grenzen).

SELECT p1.id AS anfang,
       p2.id AS ende
FROM   vw_produktion AS p1,
       vw_produktion AS p2
WHERE  p1.id < p2.id AND
       NOT EXISTS( SELECT *
                   FROM   vw_produktion AS p3,
                          vw_produktion AS p4
                   WHERE  p3.druck <= p4.druck AND
                          p4.id = p3.id - 1 AND
                          p3.id BETWEEN p1.id + 1 AND p2.id OR
                          p3.id = p1.id - 1 AND p3.druck < p1.druck OR
                          p3.id = p2.id + 1 AND p3.druck > p2.druck )

Lösung mittels Window Funktion

WITH finde_grenzen AS (
   SELECT id,
          CASE WHEN lag(  druck, 1, druck ) OVER ( ORDER BY id ) <  druck AND
                    druck <  lead( druck, 1, druck ) OVER ( ORDER BY id ) THEN NULL
               WHEN lag(  druck, 1, druck ) OVER ( ORDER BY id ) <  druck AND
                    druck >= lead( druck, 1, druck ) OVER ( ORDER BY id ) THEN 'ende'
               WHEN lag(  druck, 1, druck ) OVER ( ORDER BY id ) >= druck AND 
                    druck <  lead( druck, 1, druck ) OVER ( ORDER BY id ) THEN 'anfang'
          END AS row_type
   FROM produktion ),
 
     nummeriere_anfang AS (
   SELECT id,
          ROW_NUMBER() OVER ( ORDER BY id) AS num_start
   FROM   finde_grenzen
   WHERE  row_type = 'anfang' ),
 
     nummeriere_ende AS (
   SELECT id,
          ROW_NUMBER() OVER ( ORDER BY id ) AS num_ende
   FROM   finde_grenzen
   WHERE  row_type = 'ende' )
 
SELECT s.id AS anfang,
       e.id AS ende
FROM   nummeriere_anfang AS s
       JOIN nummeriere_ende AS e
         ON s.num_start = e.num_ende
ORDER  BY 1

Beide Lösungen werden in diesem DBFiddle gezeigt.

anfang ende
1 5
6 9



Zurück zur Übersicht