Как я могу реализовать мою функцию в моем триггере? - PullRequest
0 голосов
/ 30 октября 2019

Привет всем, я использую iban checker в PLSQL, чтобы проверить, заполнил ли пользователь правильный IBAN.

Я просмотрел функцию в интернете, которую она компилирует, теперь мне нужно включить триггер, но онвыдает ошибку, я попробовал это

, когда пользователь вводит iban nummer в приложение APEX, и ibannummers не правильно, триггер должен работать

Это моя функция:

create or replace FUNCTION CheckIBANNUMMBER(
      pIBAN IN VARCHAR2
    ) RETURN VARCHAR IS
      lResult     INTEGER;
      ResulText   Varchar(250);
      IBAN        VARCHAR2(256);
      IBAN_Digits VARCHAR2(256);
      l_mod       NUMBER;
      lTmp        VARCHAR2(8);
      lSCnt       INTEGER := 5;
      i           INTEGER := 1;

---

      FUNCTION fn_GetIBANDigits RETURN VARCHAR2 AS
        lChar   VARCHAR2(1);
        lNumber INTEGER;
        lString VARCHAR2(255);
      BEGIN
        FOR i IN 1..LENGTH(IBAN) LOOP
          lChar := SUBSTR(IBAN, i, 1);
          BEGIN
            lNumber := ASCII(lChar);
            IF lNumber > 47 AND lNumber < 58 THEN
              -- It's number 0 ... 9
              lString := lString || TO_CHAR(lNumber - 48);
            ELSE
              lString := lString || TO_CHAR(lNumber - 55);
            END IF;
          END;
        END LOOP;
        RETURN lString;
      END fn_GetIBANDigits;

---

     BEGIN
      IBAN := SUBSTR(pIBAN, 5) || SUBSTR(pIBAN, 1, 4);

      IBAN_Digits := fn_GetIBANDigits;

      LOOP
        lTmp := SUBSTR(IBAN_Digits, i, lSCnt);
        EXIT WHEN lTmp IS NULL;

        IF l_mod IS NULL THEN
          l_mod := MOD( TO_NUMBER(lTmp), 97);
        ELSE
          l_mod := MOD(TO_NUMBER( TO_CHAR(l_mod) || lTmp), 97);
        END IF;

        i := i + lSCnt;
      END LOOP;

      IF l_mod = 1 THEN
        lResult := 1;
        ResulText := 'The given IBAN is correct';
      ELSE
        lResult := 0;
        ResulText := 'The given IBAN is incorrect';
      END IF;

      RETURN(ResulText);
    END CheckIBANNUMMBER;

и это триггер, который я сделал

create or replace trigger "T_CHECKIBAN"
BEFORE
insert or update on "PAYMENTS"
for each row
begin
if CHECKIBAN(new.IBAN) = 0 then raise_application_error(-20500,'Wrong IBANNUMMBER');
end;

Ответы [ 2 ]

2 голосов
/ 30 октября 2019

Используйте виртуальный столбец и ограничение CHECK, тогда ваши проверки достоверности будут в выражении DDL для таблицы, а не в другом замке (то есть триггере):

create or replace FUNCTION CheckIBANNumber(
  pIBAN IN VARCHAR2
) RETURN NUMBER DETERMINISTIC
IS
  lResult     INTEGER;
  ResulText   Varchar(250);
  IBAN        VARCHAR2(256);
  IBAN_Digits VARCHAR2(256);
  l_mod       NUMBER;
  lTmp        VARCHAR2(8);
  lSCnt       INTEGER := 5;
  i           INTEGER := 1;

---

  FUNCTION fn_GetIBANDigits RETURN VARCHAR2 AS
    lChar   VARCHAR2(1);
    lNumber INTEGER;
    lString VARCHAR2(255);
  BEGIN
    FOR i IN 1..LENGTH(IBAN) LOOP
      lChar := SUBSTR(IBAN, i, 1);
      BEGIN
        lNumber := ASCII(lChar);
        IF lChar BETWEEN '0' AND '9' THEN
          -- It's number 0 ... 9
          lString := lString || lChar;
        ELSIF lChar BETWEEN 'A' AND 'Z' THEN 
          lString := lString || TO_CHAR(ASCII(lChar) - 55);
        END IF;
      END;
    END LOOP;
    RETURN lString;
  END fn_GetIBANDigits;

---

BEGIN
  IBAN := SUBSTR(pIBAN, 5) || SUBSTR(pIBAN, 1, 4);

  IBAN_Digits := fn_GetIBANDigits;

  LOOP
    lTmp := SUBSTR(IBAN_Digits, i, lSCnt);
    EXIT WHEN lTmp IS NULL;

    IF l_mod IS NULL THEN
      l_mod := MOD( TO_NUMBER(lTmp), 97);
    ELSE
      l_mod := MOD(TO_NUMBER( TO_CHAR(l_mod) || lTmp), 97);
    END IF;

    i := i + lSCnt;
  END LOOP;

  IF l_mod = 1 THEN
    RETURN 1;
  ELSE
    RETURN 0;
  END IF;
END CheckIBANNumber;
/
CREATE TABLE test_data (
  Country      VARCHAR2(20),
  IBAN         VARCHAR2(50),
  IBANValidity NUMBER(1) GENERATED ALWAYS AS ( CheckIBANNumber( iban ) ),
  CONSTRAINT IsValidIBAN CHECK ( IBANValidity = 1 )
);

Тогда(с тестовыми данными из Википедии):

INSERT INTO test_data ( Country, IBAN ) VALUES ( 'Belgium', 'BE71 0961 2345 6769' );
INSERT INTO test_data ( Country, IBAN ) VALUES ( 'France', 'FR76 3000 6000 0112 3456 7890 189' );
INSERT INTO test_data ( Country, IBAN ) VALUES ( 'Germany', 'DE91 1000 0000 0123 4567 89' );
INSERT INTO test_data ( Country, IBAN ) VALUES ( 'Greece', 'GR96 0810 0010 0000 0123 4567 890' );
INSERT INTO test_data ( Country, IBAN ) VALUES ( 'Romania', 'RO09 BCYP 0000 0012 3456 7890' );
INSERT INTO test_data ( Country, IBAN ) VALUES ( 'Saudi Arabia', 'SA44 2000 0001 2345 6789 1234' );
INSERT INTO test_data ( Country, IBAN ) VALUES ( 'Spain', 'ES79 2100 0813 6101 2345 6789' );
INSERT INTO test_data ( Country, IBAN ) VALUES ( 'Switzerland', 'CH56 0483 5012 3456 7800 9' );
INSERT INTO test_data ( Country, IBAN ) VALUES ( 'United Kingdom', 'GB98 MIDL 0700 9312 3456 78' );

успешно и:

 SELECT * FROM test_data;

вывод:

COUNTRY        | IBAN                              | IBANVALIDITY
:------------- | :-------------------------------- | -----------:
Belgium        | BE71 0961 2345 6769               |            1
France         | FR76 3000 6000 0112 3456 7890 189 |            1
Germany        | DE91 1000 0000 0123 4567 89       |            1
Greece         | GR96 0810 0010 0000 0123 4567 890 |            1
Romania        | RO09 BCYP 0000 0012 3456 7890     |            1
Saudi Arabia   | SA44 2000 0001 2345 6789 1234     |            1
Spain          | ES79 2100 0813 6101 2345 6789     |            1
Switzerland    | CH56 0483 5012 3456 7800 9        |            1
United Kingdom | GB98 MIDL 0700 9312 3456 78       |            1

дБ <> скрипка здесь

0 голосов
/ 30 октября 2019

Ваш отредактированный код:

CREATE OR REPLACE TRIGGER T_CHECKIBAN
    BEFORE INSERT OR UPDATE
    ON PAYMENTS
    FOR EACH ROW
BEGIN
    IF CheckIBANNUMMBER(:new.IBAN) = 0 /* new --> :new, CHECKIBAN -- > CheckIBANNUMMBER*/
    THEN
        raise_application_error(-20500, 'Wrong IBANNUMMBER');
    END IF; /* added END IF */
END;

Я удалил двойные кавычки, потому что они нужны вам, только если вы хотите использовать символы нижнего регистра.

Также обратите внимание, что ваша функция дает ResulText, хотя кажется, что он должен вернуть lResult вместо этого;и даже, вы используете varchar2 возвращаемое значение для обработки числа.

Если вы хотите, чтобы эта функция только проверяла, является ли IBAN правильным или нет, вы должны отредактировать свою функцию следующим образом (ResulTextздесь не годится):

create or replace FUNCTION CheckIBANNUMMBER(
      pIBAN IN VARCHAR2
    ) RETURN number IS /* return a number */
    ...
      RETURN(lResult); /* return 0/1 */
    END CheckIBANNUMMBER;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...