Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Niestandardowa funkcja Oracle IsNumber z precyzją i skalą

Nie sądzę, że jest jakiś prosty sposób; a wykonanie dynamicznego sprawdzenia jest stosunkowo łatwe (patrz przykład poniżej). Ale jako dość zawiłe podejście możesz przekonwertuj łańcuch na liczbę i z powrotem na łańcuch przy użyciu modelu formatu stworzonego z Twojej precyzji i skali:

> FUNKCJA TWORZENIA LUB ZAMIANA IsNumber(pVALUE VARCHAR2, pPRECISION NUMBER, pSCALE NUMBER) NUMER ZWROTUIS lFORMAT VARCHAR2(80); lNUMER NUMER; l NUMER STRINGU; FUNKCJA GetFormat(p LICZBA, s LICZBA) POWRÓT VARCHAR2 JAKO POCZĄTEK POWRÓT PRZYPADEK GDY p> =s TO LPAD('9', p - s, '9') END || PRZYPADEK GDY s> 0 TO '.' || PRZYPADEK GDY s> p TO LPAD('0', s - p, '0') || RPAD('9', p, '9') ELSE RPAD('9', s, '9') KONIEC KONIEC; END GetFormat;BEGIN -- wartości sprawdzające poprawność; potrzebne inne kontrole (dokładność <=38?) IF pPRECISION =0 TO ZWRÓĆ NULL; KONIEC JEŚLI; -- sprawdź, czy faktycznie jest to liczba lNUMBER :=TO_NUMBER(pVALUE); -- ustaw go w oczekiwanym formacie; spowoduje to błąd, jeśli dokładność jest -- przekroczona, ale skala jest zaokrąglona, ​​więc nie występuje błąd lFORMAT :=GetFormat(pPRECISION, pSCALE); lSTRING :=to_char(lNUMBER, lFORMAT, 'NLS_NUMERIC_CHARACTERS='',.'''); -- aby uchwycić zaokrąglenia skali, sprawdź większą skalę -- uwaga:oznacza to, że odrzucamy liczby, na które funkcja CAST zezwala, ale zaokrąglamy lFORMAT :=GetFormat(pPRECISION + 1, pSCALE + 1); IF lSTRING !=to_char(lNUMBER, lFORMAT, 'NLS_NUMERIC_CHARACTERS='',.''') THEN RETURN NULL; -- skala za duża END IF; ZWROT lNUMBER; WYJĄTEK, KIEDY INNI TEŻ ZWRACAJĄ NULL; -- nie liczba, precyzja zbyt duża itp.END IsNumber;/

Testowane tylko z kilkoma wartościami, ale wydaje się, że jak dotąd działa:

z t jako ( wybierz '0,123' jako wartość, 3 jako dokładność, 3 jako skalę z podwójnej unii wybierz '.123', 2, 2 z podwójnej unii wybierz '.123', 1, 3 z dual union wszystkie wybierz '.123', 2, 2 z dual union wszystkie wybierz '1234', 4, 0 z dual union wszystkie wybierz '1234', 3, 1 z dual union wszystkie wybierz '123', 2, 0 z dual union wszystkie wybierz '.123', 0, 3 z dual union wszystkie wybierz '-123.3', 4, 1 z dual union wszystkie wybierz '123456.789', 6, 3 z dual union wszystkie wybierz '123456.789', 7, 3 z dual union wszystkie wybierz '101.23253232', 3, 8 z dual union wszystkie wybierz '101.23253232', 11, 8 z dual) wybierz wartość, precyzja, skala, isNumber(wartość, precyzja, skala) isNum, isNumber2(value, Precision, scale ) isNum2 from t;WARTOŚĆ SKALA PRECYZJI ISNUM ISNUM2------------ ---------- ---------- --------- -----------0,123 3 3 0,123 0,123 0,123 2 2 0,12 0,123 1 3,1 23 0,123 2 2,12 1234 4 0 1234 1234 1234 3 1 123 2 0,123 0 3 -123,3 4 1 -123,3 -123,3 123456.789 6 3 123456.789 7 3 101.23253232 3 8 101.23253232 11 8 101.2325332 101.32532  

Korzystanie z GDY INNE nie jest idealne i można to zastąpić konkretnymi programami obsługi wyjątków. Założyłem, że chcesz, aby ta wartość zwracała wartość null, jeśli liczba jest nieprawidłowa, ale oczywiście możesz zwrócić cokolwiek lub zgłosić własny wyjątek.

isNum2 kolumna pochodzi z drugiej, znacznie prostszej funkcji, która po prostu wykonuje rzutowanie dynamicznie - czego wiem, że nie chcesz robić, to tylko dla porównania:

FUNKCJA TWÓRZ LUB ZAMIEŃ IsNumber2(pVALUE VARCHAR2, pPRECISION NUMBER, pSCALE NUMBER) RETURN NUMBERIS str VARCHAR2(80); num NUMBER;BEGIN str :='SELECT CAST(:v AS NUMBER(' || pPRECISION ||','|| pSCALE ||')) FROM DUAL'; EXECUTE IMMEDIATE str INTO num UŻYWAJĄC pVALUE; RETURN numer;WYJĄTEK GDY INNE TO RETURN NULL;END IsNumber2;/

Pamiętaj jednak, że cast zaokrągla się, jeśli określona skala jest zbyt mała dla wartości; Być może zbyt mocno zinterpretowałem „zgodne z” w pytaniu, ponieważ w tym przypadku się mylę. Jeśli chcesz coś takiego jak '.123', 2, 2 być dozwolone (podając .12 ), a następnie drugi GetFormat wywołanie i zaznaczenie „scale too large” może zostać usunięte z mojego IsNumber . Mogą być też inne niuanse, które przeoczyłem lub źle zinterpretowałem.

Warto również zauważyć, że początkowy to_number() opiera się na ustawieniach NLS dla danych i dopasowywania sesji - szczególnie separator dziesiętny; i nie pozwoli na separator grup.

Prostsze może być zdekonstruowanie przekazanej wartości liczbowej na jej wewnętrzną reprezentację i sprawdzenie, czy jest ona porównywalna z precyzją i skalą… chociaż dynamiczna trasa oszczędza dużo czasu i wysiłku.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Połącz się z bazą danych Oracle przez sterownik JDBC

  2. Wydrukuj tekst w oknie arkusza roboczego Oracle SQL Developer SQL

  3. ORA-00904 nieprawidłowy identyfikator w aliasie dekodowania

  4. Model formatu liczb TO_Char w Oracle

  5. ORA-24408:nie można wygenerować unikalnej nazwy grupy serwerów