Oracle
 sql >> डेटाबेस >  >> RDS >> Oracle

Oracle कस्टम IsNumber फंक्शन प्रेसिजन और स्केल के साथ

मुझे नहीं लगता कि कोई सरल तरीके से बनाया गया है; और गतिशील जांच करना अपेक्षाकृत आसान है (नीचे उदाहरण देखें)। लेकिन एक जटिल दृष्टिकोण के रूप में आप कर सकते थे अपनी सटीकता और पैमाने से निर्मित प्रारूप मॉडल का उपयोग करके स्ट्रिंग को एक संख्या में और वापस स्ट्रिंग में बदलें:

CREATE OR REPLACE FUNCTION IsNumber(pVALUE VARCHAR2, pPRECISION NUMBER,
  pSCALE NUMBER) RETURN NUMBER
IS
  lFORMAT VARCHAR2(80);
  lNUMBER NUMBER;
  lSTRING NUMBER;

  FUNCTION GetFormat(p NUMBER, s NUMBER) RETURN VARCHAR2 AS
  BEGIN
    RETURN
      CASE WHEN p >= s THEN LPAD('9', p - s, '9') END
        || CASE WHEN s > 0 THEN '.' || CASE WHEN s > p THEN
            LPAD('0', s - p, '0') || RPAD('9', p, '9')
          ELSE RPAD('9', s, '9') END
      END;
  END GetFormat;
BEGIN
  -- sanity-check values; other checks needed (precision <= 38?)
  IF pPRECISION = 0 THEN
    RETURN NULL;
  END IF;

  -- check it's actually a number
  lNUMBER := TO_NUMBER(pVALUE);

  -- get it into the expected format; this will error if the precision is
  -- exceeded, but scale is rounded so doesn't error
  lFORMAT := GetFormat(pPRECISION, pSCALE);
  lSTRING := to_char(lNUMBER, lFORMAT, 'NLS_NUMERIC_CHARACTERS='',.''');

  -- to catch scale rounding, check against a greater scale
  -- note: this means we reject numbers that CAST will allow but round
  lFORMAT := GetFormat(pPRECISION + 1, pSCALE + 1);

  IF lSTRING != to_char(lNUMBER, lFORMAT, 'NLS_NUMERIC_CHARACTERS='',.''') THEN
    RETURN NULL;  -- scale too large
  END IF;
  RETURN lNUMBER;
EXCEPTION
  WHEN OTHERS THEN
    RETURN NULL;  -- not a number, precision too large, etc.
END IsNumber;
/

केवल कुछ मूल्यों के साथ परीक्षण किया गया लेकिन अब तक काम करता प्रतीत होता है:

with t as (
  select '0.123' as value, 3 as precision, 3 as scale from dual
  union all select '.123', 2, 2 from dual
  union all select '.123', 1, 3 from dual
  union all select '.123', 2, 2 from dual
  union all select '1234', 4, 0 from dual
  union all select '1234', 3, 1 from dual
  union all select '123', 2, 0 from dual
  union all select '.123', 0, 3 from dual
  union all select '-123.3', 4, 1 from dual
  union all select '123456.789', 6, 3 from dual
  union all select '123456.789', 7, 3 from dual
  union all select '101.23253232', 3, 8 from dual
  union all select '101.23253232', 11, 8 from dual
)
select value, precision, scale,
  isNumber(value, precision, scale) isNum,
  isNumber2(value, precision, scale) isNum2
from t;

VALUE         PRECISION      SCALE      ISNUM     ISNUM2
------------ ---------- ---------- ---------- ----------
0.123                 3          3       .123       .123 
.123                  2          2                   .12 
.123                  1          3       .123            
.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.232532 101.232532 

WHEN OTHERS का उपयोग कर रहे हैं आदर्श नहीं है और आप इसे विशिष्ट अपवाद हैंडलर से बदल सकते हैं। मैंने माना है कि यदि संख्या मान्य नहीं है, तो आप इसे शून्य वापस करना चाहते हैं, लेकिन निश्चित रूप से आप कुछ भी वापस कर सकते हैं, या अपना अपवाद फेंक सकते हैं।

isNum2 कॉलम एक दूसरे, बहुत सरल कार्य से है, जो सिर्फ गतिशील रूप से कास्ट कर रहा है - जो मुझे पता है कि आप ऐसा नहीं करना चाहते हैं, यह सिर्फ तुलना के लिए है:

CREATE OR REPLACE FUNCTION IsNumber2(pVALUE VARCHAR2, pPRECISION NUMBER,
  pSCALE NUMBER) RETURN NUMBER
IS
  str VARCHAR2(80);
  num NUMBER;
BEGIN
  str := 'SELECT CAST(:v AS NUMBER(' || pPRECISION ||','|| pSCALE ||')) FROM DUAL';
  EXECUTE IMMEDIATE str INTO num USING pVALUE;
  RETURN num;
EXCEPTION
  WHEN OTHERS THEN
    RETURN NULL;
END IsNumber2;
/

लेकिन ध्यान दें कि cast राउंड यदि निर्दिष्ट पैमाना मान के लिए बहुत छोटा है; हो सकता है कि मैंने प्रश्न में "अनुरूप" की बहुत दृढ़ता से व्याख्या की हो क्योंकि मैं उस मामले में त्रुटि कर रहा हूं। अगर आपको '.123', 2, 2 . जैसा कुछ चाहिए अनुमति दी जानी चाहिए (.12 देकर ) फिर दूसरा GetFormat कॉल और 'स्केल टू लार्ज' चेक को मेरे IsNumber . से हटाया जा सकता है . अन्य बारीकियां भी हो सकती हैं जिन्हें मैंने याद किया है या गलत व्याख्या की है।

यह भी ध्यान देने योग्य है कि प्रारंभिक to_number() डेटा और सत्र मिलान के लिए एनएलएस सेटिंग्स पर निर्भर करता है - विशेष रूप से दशमलव विभाजक; और यह समूह विभाजक को अनुमति नहीं देगा।

पारित संख्यात्मक मान को उसके आंतरिक प्रतिनिधित्व में विघटित करना और यह देखना आसान हो सकता है कि क्या यह सटीकता और पैमाने के साथ तुलना करता है ... हालांकि गतिशील मार्ग बहुत समय और प्रयास बचाता है।




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. GTT तालिका आँकड़े और SYS.WRI$_OPTSTAT_TAB_HISTORY

  2. Oracle 2 तारीखों के बीच महीनों के अंतिम दिनों को कैसे सूचीबद्ध करें?

  3. Oracle में दशमलव के बिना संख्या को प्रारूपित करने के 4 तरीके

  4. ओरेकल में कई रिकॉर्ड डालें

  5. Oracle में सप्ताह का पहला और अंतिम दिन कैसे प्राप्त करें?