Blog programisty w Oracle PL/SQL

Jest to blog eksperymentatora programisty w PL/SQL dla Oracle. Wszystkie kody tutaj zamieszczone mogą być dowolnie wykorzystywane i zmieniane. A jeśli Ktoś z Gości znajdzie błąd, będę niezwykle wdzięczny...
Zapisz

Szukaj na tym blogu

piątek, 1 lipca 2011

Algorytmy rekurencyjne w SQL

 Możliwe?? Tak, wystarczy polubić klauzulę model..
Poniżej w dwóch zapytaniach są  algorytmy zapisane w wersji rekurencyjnej
  • ciąg Fibonacciego
  • silnia
  • algorytm Euklidesa do wyznaczania największego wspólnego podzielnika
Przedstawione są dwie techniki:
  •  modele iteracyjne -znakomicie nadają się do implementacji jednoargumentowych funkcji rekurencyjnych, a ich zapis jest niemal intuicyjny. Niestety przy większej liczbie parametrów pojawiają się problemy cyklicznego wyliczania komórek
  • modele nieiteracyjne  - formuły są nieco bardziej zawiłe, ale można obsłużyć funkcje wieloargumentowe
    SELECT                                                    
          d  , f AS FIBBONACCI,
          S AS SILNIA
      FROM   (SELECT   0 d  FROM DUAL)
    MODEL
       DIMENSION BY (0 d)
       MEASURES (0 f, 0 s)
       RULES
          ITERATE (10000000) UNTIL (ITERATION_NUMBER = 50)
           (f [ITERATION_NUMBER] =
                                CASE ITERATION_NUMBER
                                    WHEN 0 THEN 0
                                    WHEN 1 THEN 1
                                  ELSE
                                    f[ITERATION_NUMBER - 2] + f[ITERATION_NUMBER - 1]
                                END,
          s [ITERATION_NUMBER] =
                      CASE ITERATION_NUMBER
                        WHEN 0 THEN 1
                        ELSE           
                        ITERATION_NUMBER * s[ITERATION_NUMBER - 1]
                      END)




    Poniższy przykład można jeszcze nieco uprościć :)

    SELECT   L1, L2, NWD
      FROM   (SELECT   L1, l2
                FROM   (    SELECT   LEVEL - 1 L1
                              FROM   DUAL
                        CONNECT BY   LEVEL <= 20),
                       (    SELECT   LEVEL - 1 L2
                              FROM   DUAL
                              CONNECT BY   LEVEL <= 20))
    MODEL
       DIMENSION BY (L1, L2)
       MEASURES (0 NWD )
       RULES SEQUENTIAL ORDER
          (NWD [ANY, ANY] =
                CASE
                   WHEN CV (l2) = 0
                   THEN
                      CV (l1)
                   WHEN CV (l2) <= CV (l1)
                   THEN
                      NWD[CV (l2), MOD (CV (l1), CV (l2))]
                END,
          NWD [ANY, ANY] =
                CASE
                   WHEN CV (l2) > CV (l1) THEN
                            NWD[CV (l2), CV (l1)]
                   ELSE NWD[CV (l1), CV (l2)]
                END)