Kategorie szkoleń | Egzaminy | Kontakt
  • 3
  • 0
  • 209

Drodzy Użytkownicy.

Bardzo proszę o pomoc w prawidłowym zbudowaniu formuły SQLowej działającej na Informixie.

Formuła sprawdza poprawność PESEL.

Korzystałam z funkcji CAST aby zmienić typ danych i SUBSTR aby wyciągnąć z PESELa potrzebne cyferki.

W dalszym ciągu wyskakuje błąd "character to numeric conversion error".

Nie działa ani int, ani bigint, char, nchar, nie mam pojęcia który typ jest poprawny, powoli powątpiewam w konstrukcję formuły.

 

SELECT pesel, (CAST(SUBSTR(pesel ,1,1) as INT)*1)
+(CAST(SUBSTR(pesel ,2,1) as INT)*3)
+ (CAST(SUBSTR(pesel ,3,1) as INT)*7)
+ (CAST(SUBSTR(pesel ,4,1) as INT)*9)
+ (CAST(SUBSTR(pesel ,5,1) as INT)*1)
+ (CAST(SUBSTR(pesel ,6,1) as INT)*3)
+ (CAST(SUBSTR(pesel ,7,1) as INT)*7)
+ (CAST(SUBSTR(pesel ,8,1) as INT)*9)
+ (CAST(SUBSTR(pesel ,9,1) as INT)*1)
+ (CAST(SUBSTR(pesel ,10,1) as INT)*3)
% 10

FROM umowy.

 

Proszę Mądre Głowy o jakąś wskazówkę.

Z góry ogromnie dziękuję!

Joanna_Wieczorek
  • Zapytał
  • @ Joanna_Wieczorek | 13.04.2016
    • 1
    • 1
    • 1

Odpowiedzi (3)

  • 3

Postaram się wyjaśnić tę sprawę.
Domyślam się z konstrukcji polecenia SQL, że Autorce pytania chodzi o zdefiniowanie wyrażenia, które w wyniku przekaże cyfrę kontrolną numeru PESEL.
Jako przykład użycia podano polecenie SQL, w którym odczytywane są wszystkie wiersze tabeli UMOWY i dla każdego wiersza wyświetlana jest wartość zawarta w kolumnie PESEL oraz OBLICZONA cyfra kontrolna, którą pewnie potem należy porównać z ostatnią cyfrą numeru PESEL.
W przedstawionym poleceniu SELECT jest błąd polegający na użyciu nieistniejącego operatora '%' (procent).
Próba wykonania tego polecenia w dbaccess zwraca błąd:
-202  An illegal character has been found in the statement.

Jak przypuszczam Autorce chodziło o wyznaczenie ostatniej cyfry z wyliczonej sumy, czyli wykonanie operacji MODULO 10.
W przypadku SQL Informix należy w takim przypadku użyć funkcji MOD. Zatem poprawna postać przedstawionego polecenia powinna wyglądać następująco:

SELECT pesel,
MOD(10-MOD((CAST(SUBSTR(pesel ,1,1) as INT)*1)
+ (CAST(SUBSTR(pesel ,2,1) as INT)*3)
+ (CAST(SUBSTR(pesel ,3,1) as INT)*7)
+ (CAST(SUBSTR(pesel ,4,1) as INT)*9)
+ (CAST(SUBSTR(pesel ,5,1) as INT)*1)
+ (CAST(SUBSTR(pesel ,6,1) as INT)*3)
+ (CAST(SUBSTR(pesel ,7,1) as INT)*7)
+ (CAST(SUBSTR(pesel ,8,1) as INT)*9)
+ (CAST(SUBSTR(pesel ,9,1) as INT)*1)
+ (CAST(SUBSTR(pesel ,10,1) as INT)*3),10),10)
FROM umowy;

Przy okazji wprowadzono korekty do tego wyrażenia:
- cyfra kontrolna PESEL wynika z różnicy między liczbą 10, a wyliczoną ostatnią cyfrą sumy,
- wprowadzono podwójne użycie funkcji MOD dla otrzymania poprawnego wyniku w przypadku, gdy wyliczona ostatnia cyfra sumy wynosi 0.
W rzeczywistości algorytm sprawdzenia powinien jeszcze obejmować formalną poprawność zapisu daty urodzenia oraz (o ile to możliwe) także płeć.

Osobnym zagadnieniem jest sygnalizowany błąd:


-1349    Character to numeric conversion error.
A character value is being converted to numeric form for storage in a
numeric column or variable. However, the character string cannot be
interpreted as a number. It contains some characters other than white
space, digits, a sign, a decimal, or the letter e, or else the parts
are in the wrong order so that the number cannot be deciphered.

Pojawienie się tego błędu wskazuje na niepoprawną zawartość kolumny PESEL.
Być może są tam wprowadzone znaki, które nie mogą być konwertowane na wartość numeryczną, np. litery.
Proszę to sprawdzić prostym zapytaniem:
SELECT pesel, CAST(pesel as BIGINT) FROM umowy;


Jeśli wystąpią znaki uniemożliwiające konwersję zostanie zwrócony stosowny błąd (-1213), a wykonanie operacji zatrzyma się na ostatnim poprawnym wierszu.

Z przyjemnością odpowiem na dodatkowe pytania.
Pozdrawiam.

  • Odpowiedział
  • @ | 04.05.2016
  • TRENER MODERATOR ALTKOM AKADEMII
  • 0

Bardzo dziękuję Panie Marku za tak profesjonalną odpowiedź.

Odpowiadając na Pana pytania - owszem, tabela PESEL zawiera różne znaki, tj litery, myślniki, więc typ varchar.

Zwykły CASE varchar to INT nie działa..

Mam pomysł aby zastosować 2 x CASE:

- żeby odrzucone zostały te PESELe które są niepoprawne (różna długość, zawierające litery) wraz z informacją o błędzie, np. pesel niepoprawny-niedozwolone znaki.

- żeby brać pod uwagę tylko te liczby które mają poprawną długość PESEL, bez liter, w konsekwencji, żeby zwrócił wynik czy pesel jest poprawny czy posiada błędną cyfrę kontrolną

Natomiast nie wiem jak to "ubrać" w język SQL Informix. Dotychczasowe wersje nie były poprawne.

Niestety ISNUMERIC nie działa w Informix.

Panie Marku, wydaje mi się, że powinna być to funkcja lub procedura.

Z góry uprzejmie dziękuję za dodatkowe wskazówki.

 

Joanna_Wieczorek
  • Odpowiedział
  • @ Joanna_Wieczorek | 11.05.2016
    • 1
    • 1
    • 1
  • 0

Pani Joanno.

Obawiam się, że problem, który Pani obecnie przedstawia trochę wybiega poza formułę krótkich pytań i odpowiedzi Quorum.
Żeby można było przedstawić optymalne rozwiązanie, to powinniśmy chyba zacząć od początku, czyli od szczegółowego opisania typu danych oraz rzeczywistej zawartości kolumny PESEL w tabeli UMOWY, oraz opisu zadania jakie ma Pani do wykonania (tzw. problem do rozwiązania) - czy tylko wylistować, czy poprawić, czy "wyczyścić dane", czy przepisać do innej tabeli?
A może w kolumnie PESEL są zapisane zamiennie PESEL lub np. NIP (podobnie jak w formularzach PIT) i nie można modyfikować zawartości?
Na tak szczegółowe konsultacje zapraszam już do korespondencji mailowej.

W tym wątku jeszcze kilka uwag, które mogą być pomocne w rozwiązaniu tego zagadnienia, a przydatne także dla innych użytkowników w podobnych przypadkach.

Możemy filtrować wybierane dane w taki sposób, aby nie uwzględniać w odpowiedzi wierszy, w których w kolumnie PESEL są znaki, których tam być nie powinno, np. litery.
SELECT pesel FROM UMOWY WHERE pesel NOT MATCHES '*[a-zA-Z]*';
Jeśli jeszcze będą tam inne znaki, to możemy je również dodać do listy w nawiasach kwadratowych.
Czasem musimy się podeprzeć znakiem znakiem specjalnym "/" dla wyeliminowania znaków zastrzeżonych.
Na przykład, jeśli chcemy uwzględnić na naszej liście znak pauzy "-", to musimy napisać tak:
SELECT pesel FROM umowy WHERE pesel NOT MATCHES '*[a-zA-Z/-]*';

W SQL Informix rzeczywiście nie ma funkcji ISNUMERIC, ale łatwo można ją napisać samodzielnie z uwzględnieniem rzeczywistych potrzeb i typów danych.
Poniżej przykładowa definicja:

CREATE FUNCTION IsNumeric(InputStr VARCHAR(20)) RETURNING SMALLINT;
 DEFINE IsNum SMALLINT;
 DEFINE LocBigInt BIGINT;
 LET IsNum = 1;
 BEGIN
  ON EXCEPTION IN (-1213)
   LET IsNum = 0;
  END EXCEPTION
  LET LocBigInt = CAST(InputStr AS BIGINT);
 END
 RETURN isNum;
END FUNCTION;

Ta funkcja zwraca wartość 1 (SMALLINT) jeśli łańcuch podany w argumencie funkcji jest możliwy do konwersji na BIGINT, a 0 (SMALLINT), jeśli to nie jest możliwe.
Proszę spróbować:
SELECT pesel, ISNUMERIC(pesel) AS isnumeric FROM umowy;
W wyniku w kolumnie "isnumeric" powinny być wartości 1 w tych wierszach, które mogą być konwertowane na liczbę typu BIGINT.
Funkcję tę można też użyć w klauzuli WHERE, np:
SELECT pesel FROM UMOWY WHERE IsNumeric(pesel) = 1;
Oczywiście klauzulę WHERE można rozszerzać na np. sprawdzanie ilości znaków, itd.

Pozdrawiam i życzę sukcesów w pracy z Informix.

 

  • Odpowiedział
  • @ | 17.05.2016
  • TRENER MODERATOR ALTKOM AKADEMII