Prosta walidacja numeru PESEL z wykorzystaniem wyrażeń regularnych
Przyjmijmy następujące założenia dla funkcji sprawdzającej:
- korzystamy z bazy w wersji 11g lub nowszej
- parametr funkcji powinien składać się z 11 cyfr dowolnie porozdzielanych dowolną ilością spacji i myślników oraz dowolnych znaków nie będących cyframi. Wielkość parametru może obejmować maksymalną wielkość dopuszczalną przez typ VARCHAR2 w języku PL/SQL
- funkcja zwraca 1 jeśli PESEL jest poprawny, 0 jeśli jest niepoprawny. Celowo nie wybrałem zwracania wartości BOOLEAN, gdyż takowa nie jest obsługiwana w zapytaniach SQL
Typ SIMPLE_INTEGER został zastosowany ze względu na szybkie maszynowe rozwinięcie na poziomie kodu interpretowanego i natywnego i uniknięcie niepotrzebnych konwersji.W jaki sposób można poniższą funkcję jeszcze przyśpieszyć. Widzę następującą możliwość: opakowując w pakiecie, wówczas można inicjalizację tabeli wag umieścić w części inicjalizacyjnej pakietu oraz kompilację natywną...
Zamieszczony kod może być dowolnie wykorzystywany i przerabiany.
CREATE OR REPLACE FUNCTION FDB_Validate_PESEL(pc_PESEL VARCHAR2) RETURN INTEGER
IS
type t_Weights is varray(11) OF SIMPLE_INTEGER;
vt_Weights t_weights := t_weights(1, 3, 7, 9, 1, 3, 7,9,1,3,1);
vn_CheckSum SIMPLE_INTEGER := 0;
vc_PESEL VARCHAR2(11) ;
BEGIN
--
IF NVL(REGEXP_COUNT( pc_PESEL, '[[:digit:]]'),0) <> 11 THEN
RETURN 0;
END IF;
----
vc_PESEL := REGEXP_REPLACE( pc_PESEL, '[^[:digit:]]', '');
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
RETURN 1;
ELSE
RETURN 0;
END IF;
EXCEPTION WHEN OTHERS THEN
RETURN 0;
END;
Nie sprawdzałem (pracuję na 10g aktualnie), ale wydaje mi się, że w 11g można zapisać (LENGTH(REGEXP_REPLACE() w taki sposób: REGEXP_COUNT() i usunąć negację z wyrażenia regularnego - powinno być równoważne i nieco krótsze.
OdpowiedzUsuńSłuszna i trafna uwaga - zastosowałem. Cały kod na moim blogu powstał dla Oracle 11g, nie mam możliwości sprawdzenia na wersji 10
OdpowiedzUsuńSprawdzalem i na wersji Oracle 10g nie dziala. W 10 nie ma funkcji REGEXP_COUNT()
OdpowiedzUsuńDla wersji Oracle 10 poprawilem nieco Twoj kod - http://pastebin.com/n8bVMDMe