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

środa, 19 października 2016

Pseudominizacja numeru PESEL - przykład rozwiązania

Problem pseudominizacjidanych  występuje często kiedy dane z systemów zawierających dane osobowe lub dane wrażliwe musimy  udostępnić osobom  trzecim,  ukrywając te dane i możliwość identyfikacji osób

Założenia algorytmu:
  • nowy PESEL dla danej osoby zachowuje informacje o płci i o dacie urodzenia
  • numer ewidencyjny w obrębie daty urodzenia  jest numerowany od stałej cn_DayIndex w dół
  • zakłada się, że parametry są poprawne -  parametr pc_PESEL nie jest walidowany
  • na wejściu algorytmu powinien być zbiór SELECT DISTINCT PESEL FROM....
  • przed  wykonaniem anonimizacji należy wykonać blok:
              BEGIN
                    PCKG_ANONYMIZE_DATA.PDB_CLEARINTERNALDATA;
             END;   

Jak to działa??
Poniższe zapytanie generuje nowy PESEL dla Jarosława K.
SELECT PCKG_ANONYMIZE_DATA.FDB_GenerateNewPESEL('49061804592') FROM DUAL
Otrzymamy       49061899990
Wywołajmy teraz  funkcję  5 razy
SELECT PCKG_ANONYMIZE_DATA.FDB_GenerateNewPESEL('49061804592') FROM DUAL
CONNECT BY LEVEL <= 5
Jako wynik otrzymamy
49061899976
49061899952
49061899938
49061899914
49061899891
Czyli widzimy, że dla kolejnych nr  PESELw obrębie daty urodzenia generowane są kolejne nowe PESELE, ale nie jest sprawdzana unikalność nr PESEL na wejściu..

Czy nowe nr PESEL zapewniają pełną pseudonimizację ze względu na ten nr. Nie..,  Jeśli np wiemy , ze  w bazie było dwóch  klientów  w wieku po 80 lat, to możemy z dużym prawdopodobieństwem ich  zidentyfikować, jeśli maja różne daty urodzenia. Dla  lat, w których jest dużo klientów  w poszczególnych dniach będzie na podstawie  tylko nr  PESEL niemożliwe

CREATE OR REPLACE PACKAGE PCKG_ANONYMIZE_DATA IS
    PROCEDURE
PDB_ClearInternalData;  
    FUNCTION FDB_GenerateNewPESEL(pc_PESEL VARCHAR2) RETURN VARCHAR2 ;
    PRAGMA RESTRICT_REFERENCES (FDB_GenerateNewPESEL, WNDS);
END;
/
CREATE OR REPLACE PACKAGE BODY PCKG_ANONYMIZE_DATA
IS
   TYPE
T_NUMBERS IS TABLE OF VARCHAR2 (4)
      INDEX BY VARCHAR2 (6);

   Vt_Numbers             T_NUMBERS;
   cn_DayIndex   CONSTANT NUMBER (4) := 9999;
/************************************************************************/
   PROCEDURE PDB_ClearInternalData
   IS
   BEGIN

      Vt_Numbers.DELETE;
   END;
/************************************************************************/
   FUNCTION FDB_GenerateNewPESEL (pc_PESEL VARCHAR2 )
      RETURN VARCHAR2
   IS
      TYPE
t_Weights IS VARRAY (10) OF SIMPLE_INTEGER;

      vt_Weights    t_weights
                       := t_weights (1,3,7,9,1,3,7,9,1,3);
      vn_CheckSum   SIMPLE_INTEGER := 0;
      vc_PESEL      VARCHAR2 (15);
      vc_DayIndex   NUMBER (4) := '0';
      vn_Plec       NUMBER (1);
   BEGIN
      vc_Pesel := SUBSTR (pc_PESEL, 1, 6);
      vn_Plec := SUBSTR (pc_PESEL, 10, 1);
--------------------
      IF  vt_Numbers.exists(vc_PESEL ) THEN              
        vc_DayIndex := NVL (Vt_Numbers (vc_Pesel) - 1, cn_DayIndex);        
      ELSE  
        vc_DayIndex := cn_DayIndex;           
      END IF;
--------------------
      IF MOD (vc_DayIndex, 2) <> MOD (vn_Plec, 2) THEN
         vc_DayIndex := vc_DayIndex - 1;
      END IF;
--------------------
      Vt_Numbers (vc_Pesel) := vc_DayIndex;
      vc_Pesel :=vc_Pesel || LPAD (TO_CHAR (vc_DayIndex), 4, '0');
--------------------
      FOR i IN 1 .. vt_Weights.COUNT
      LOOP
         vn_CheckSum :=
              vn_CheckSum
            + TO_NUMBER (SUBSTR (vc_PESEL, i, 1)) * vt_Weights (i);
      END LOOP;
--------------------
      IF MOD (vn_CheckSum, 10) = 0 THEN         vc_PESEL := vc_PESEL || '0'; 
    ELSE
         vc_PESEL := vc_PESEL || (10 - MOD (vn_CheckSum, 10));
      END IF;
--------------------
      RETURN vc_Pesel;
   /*EXCEPTION WHEN OTHERS THEN
      RETURN NULL;*/

   END;
/*******************************************************************/
BEGIN  
    Vt_Numbers.DELETE;
END;
/

piątek, 1 lipca 2016

Obliczanie liczby pi w SQL

Kolejnym zastosowaniem klauzuli MODEL będzie napisanie prostego zapytania wyliczającego  liczbę pi  ( ludolfinę ) z zadaną dokładnością z wykorzystaniem algorytmu Leibniza
 data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAhAAAABJCAMAAABbwO+tAAACBFBMVEX////S0tKoqKb///ylpaXx+/////r8//////j9/f74///Hr45uVEAhVo3o8fvZvaBWX4XbvrbY6PdZY4zavqXbv7H///M1UX3f6/bl/v/z7erf1Mipqrfw8/nLysxVYY2pzupMRlNpaGRUWmrJnXDLy8WaxeilpJ3v5dSrxuZkJyH//+17eXibmp60qJl/MRjs4Nhhiqc4ODjG0t1UfJ1VGQS/vKyAMiFXUmzT9v+8uLrRv7zLyNG3tLTD2/BjiaW8rJKnjn9ZQiZ0rc68r4jCl4hjo9ZsOiH//+LA6P2+nZr+47WruLDu79be17ja3eyTfGBFXnWIZV5eIADVyLKnmXInSWMAM0d6Uzmvw9zboWkvPJaRb15aiLZXdIqQhG7j3K5DNmT75Kescz0vEzgWKUYAJGO32eJrSFHms3zjsmobN27wyJKSt9OBiY9pfpCJnqtzISdmRW6MWCOQiLqNeHZ4iIl+ueejaycAE37/9cgAF0HVu3xfTjuaeEuQXDuBncvCj0YKAACvYzmwe1d4l5oRaKstPlVNQjOpemc/W2esi1FRKk9/lspYACh1P0fMsLRXEkqck6dTDBddfsAAACEAQo5zAAB5Zkw/Ext/azYeHx0zGACdTjMAAD0xQ0Y8KgCUZ2C4jmsoPWVGDxpznLQsACKENgCYqc0tN0pwRiq0tZPIa4CqAAAHsElEQVR4nO2a+V8TRxiHJ9kQNoCCCGvchDVyNKtLaBSLkJACXoQrgsaz4IUWbSGora1StVWwrdW21pPW2lasLbX/ZGd2khDhnRUUtH72fX5IwjvHDjvffeedd4cQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQ5PUgP173pofw+rkx/aZH8L/FeLSDEEmN+vOgUtXnr1hKOysKx3aKh+dRyw6IS4XjTpfqt1cLLrofFQEjTw3QT6VtywbwxhYWLVu+lHZKcvLJ++LxhVvv7BCXCsdtYrROPhEIgiQbLS5qZ5J9pezL3doC3lhpRQk4kYtlZ5cOn7SYG4k8shCEcNyc/GMfiwQhFd4vsOjXtijXuet0bxM8acVr4IlcLDslYSUIIo9bCkI0bk6XUBDEOPOORUPbUlziNb/d2wRPWrngyV4sO8XSQxDyAkFYeQjSJVwyCLl4waqlXRnckG9+S62CJ61sJTyRi2Wn6JaCkCwFIRw3R7xkUOf4c8CipU2J/5necgqftLKVpUtqJ0wQAYshusd3eMSlkrWHOGbhIcj4BowiZtO1r4P/kEVrcfkq75LaCVsyAhZDtF4yhOPmDFt4CHKxTzgkG6E+lw44eJ9/G48rKxubgOrVVZVrA0topwzToq1wEUXvr6wcFU6c0S8YNy9tW1tZVS/u+ibuPIn7XG6aR7Lc0s1B8lg4b+hi6sLqp5FFKaxFbqv+aJHysgvDv+XehHj7ggQRjSxs0dUtsogWTHW8TCtOYjp/3nXVL0fmX/ktx2My1z52tjI3ZWu0L2gvXu5fmCDKT7+UICZeRRCfzr+ucvmpXaLK4ku/Pnz4exUNqCSfptU0aBHNXIaVx0P9uR5i7I/AQrqN+hf2RPlezkO8LkHIU6dtIggjODQ1FCpVCUvthjhmbFU2onBBlPFnPSuImNPlcrocrEFYq9Eo9XnP21WHVtOZ0hyauUhHqJXbSVhz0AY1zaZdy9aXHZpWl6rXNC8TkeZy0gYar8/6d/D6DtPO2jidTmbQadHlEfrBxqeadl4eU81OHXxwpjBDTt6S1WGlnqim/buS1mAZj4pItowPSA+yfW9ZPe047DQfD/mGXTyEO0856/NnEkGy+cluoe9opOFZC9uIDV4wb0VXRhAOE3ZXlYZQMBQMhnjzGXu4LhScrHIFQzuft5MorR4KBV3eWf3EgsE2Vt+cPHWmvo/3HzLrc3saZkiEgs5no/TyebNL2QJoBHnjA56Zi3GYvNS6kOvwXnpJtu3w5JayC3ddZY7n7zX0H0/+ZW4vFNsIgsaOd7tGzRlVL280+YeFDmos1r1+1JxRHl+AS4ZnpnyWPQrHEB6wOmExxHKgRNR/trS6w7LYorHlksGb5nzKU7YJKo0HAb0EzAyWF03npJCN9kDmp1QB35ywY2YjlxNUqhVEhXLR4YqcaFbPCSrDDkE8oeal+8uSG0OYdtWxEx4cK1XUAmlme/ucIKhZUivg8JoVf2IfQcRWGxFovpROlz8nG2Ns/jxtrzv3FJywztN1tVllrZgRRHVV6iyQEJLPVNXWpjJXYB4iTVkqOAolDfVg4xBbj2pzTm1NBDK/uF1PdfdD+xW9btcI9XKVn9WmsnKaEYRcfi7lpR6SDmgUTk7ZadvJzhHMh/EB/u2u6QVTwPGrXxntA5m/VG/2UbsymmoG7uZYX3f3jQsZGSiOjIDGNgbc56Gch9pwiQpCr1mfs/9NZBOT3H5xb9PwF8DOQ/UVbaWxwfF0XGPSk/3pdrT2lRJ1V7d/z174NYq6HxNTszn4QXrKJPidgNHZASevtjeBWciudcQ4CXiOU/uayEfgewV9FxUEUTbDCRHTnvAXDJ+AtqJKLxPEgEew2h3payJ6MyH9AbCYJI5i6no2x06kZ08SnTwK934IzePgocOHwPfZ8vYRwDpMr3MQFETPJBMEeVeQITPtanI3mFHlgjh+rXYaDBIS/DDYQVE29mKf8C2IbTHupCdCdPLI7WvdGwDsvlL3+btQAziYNXZP6+2wIIqYIGSBh+B2NXq5BXq/ZQpCaS5IXIKGSD0EG0r8J9ELz/MDttl1zp8r6TMBgoMmBg3vx5fNvaPG7dXkFDTBUiHsacJtp6tBQcS5hxAIwvQQPRVk7CrkdwwqCDl5gMR/Ad+Wcg9RvAzumcTxgAyAnjl8vK0FelxO3QvIg8BEDt/rIFeWAS2UG6CwpFteMgi67viuFy4ZDw4V0OAWiBPkfiqI/vvE2A8K4kijlx0a/RrumZyCxm97lF7zTsvRw6v8QEww9m0g+cP3c+3xovrkTWgOBYKgE1r4HbRi63VbrtUTveG9TfVAHGDa8ycaHdugk/pqcnJTc0F5i9pWAiwobt+eb/xe+g8KBNGDh2xBElVsnuRoJBKDgkSfywWmJ6kd3LPJyXoo5HffCsXAvZ8ei8SoIOjVQUGYdqXBeRvKJCh00M15SrTOBQUYbl8kEvESdzIAXZdIU5vQQUAoE6I1liMJcjeSIH8syn+81FGZbGPL1qIhpoFLy54Iz3jaHPn6gA2Po/vwtJQQOWTD/EzhARtlrRfMK7nztxP3mx4AgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAIsuj8B0xVNmtrAUR1AAAAAElFTkSuQmCC
Zapytanie zwraca cztery kolumny, druga to wartość liczby PI obliczona z funkcji arcus sinus, trzecia
to przybliżona wartość pi obliczona ze wzoru Leibniza, czwarta to  moduł różnicy pomiędzy  kolumną drugą a trzecią. Zwiększając dokładność o kolejne rzędy wielkości  odczujemy istotne  wydłużenie działania zapytania. Iterowanie zakończy się w momencie spełnienia jednego z warunków: osiągniemy zakładaną dokładność lub liczba iteracji osiągnie  wartość umieszczona w nawiasie po  słowie kluczowym ITERATE .
Jak możemy się łatwo przekonać obserwując ostatnia kolumnę, jest to algorytm wolnozbieżny, jego zastosowanie  ma tylko charakter edukacyjny, aby pokazać możliwość  obsługi ciągów liczbowych przez iteracyjną klauzulę MODEL ..

SELECT
      d  + 1 "Nr iteracji",
      PI_ASIN "Pi z funkcji asin",
      4 *PI_COMPUTED "Wartość obliczona",
      DIFF "Różnica"
  FROM   (SELECT   0 d  FROM DUAL)
MODEL
   DIMENSION BY ( 0 d)
   MEASURES (
   CAST( 0 AS  NUMBER)  PI_ASIN,
   CAST( 0 AS  NUMBER)  PI_COMPUTED,
   CAST( 0 AS  NUMBER)  DIFF )   
   RULES
      ITERATE (1000000000) UNTIL (ITERATION_NUMBER >1 AND  DIFF [ITERATION_NUMBER ] < 0.01)
       (      
        PI_ASIN[ ITERATION_NUMBER ] =ASIN(1)*2,      
        PI_COMPUTED[ ITERATION_NUMBER]  =
            CASE ITERATION_NUMBER
                                WHEN 0 THEN 1
                    ELSE
                     PI_COMPUTED[ ITERATION_NUMBER -1 ] + POWER( -1, ITERATION_NUMBER) / (2*ITERATION_NUMBER +1)                   
           END,                     
       DIFF [ ITERATION_NUMBER] = ABS(4*PI_COMPUTED[ ITERATION_NUMBER ] - PI_ASIN[ITERATION_NUMBER] ))

wtorek, 21 czerwca 2016

Wyszukiwanie kodów błędów Oracle w tekście


Poniższe zapytanie ma za zadanie wyszukiwać w wejściowym tekście różnych kodów błędów Oracle. Kody błędów wyszukiwane są za pomocą wyrażeń regularnych. Użycie funkcji uprościło zapytanie i umożliwiło wykonanie  DISTINCT

WITH FUNCTION PARSE(ARG VARCHAR2) RETURN VARCHAR2 AS
vc_Wynik VARCHAR2(100 CHAR);
BEGIN
  SELECT LISTAGG(BLAD, ',')  WITHIN GROUP( ORDER BY 1) INTO vc_Wynik
FROM
    (SELECT  DISTINCT REGEXP_SUBSTR( arg, 'ORA[[:punct:]][[:digit:]]{4,5}',1, LEVEL) BLAD    FROM DUAL
        CONNECT BY LEVEL <=  REGEXP_COUNT( arg, 'ORA[[:punct:]][[:digit:]]{4,5}'));
   RETURN vc_Wynik;     
END;
SELECT PARSE( 'pierwszy ORA-33344 Drugi ORA-2342 Trzeci ORA ORA-66666--')  FROM DUAL