Неверное количество или типы аргументов в вызове '||' - PullRequest
0 голосов
/ 20 марта 2020

Мы должны прочитать текстовый файл, вставить эти данные в таблицу, заботясь об исключениях. Вот код моей функции:

set serveroutput ON; 
CREATE OR replace FUNCTION Order_func(ldir  VARCHAR2, 
                                      lfile VARCHAR2) 
RETURN BOOLEAN 
AS 
  result       BOOLEAN; 
  f            utl_file.file_type; 
  s            VARCHAR2(200); 
  v_row        VARCHAR2(2000); 
  v1           NUMBER; 
  v2           NUMBER; 
  v3           NUMBER; 
  v4           DATE; 
  v5           DATE; 
  v6           NUMBER; 
  v7           NUMBER; 
  v8           NUMBER; 
  v9           NUMBER; 
  customer_error EXCEPTION; 
  employee_error EXCEPTION; 
  item_error EXCEPTION; 
  customerids  NUMBER; 
  employeeids  NUMBER; 
  inventoryids NUMBER; 
BEGIN 
    SELECT cno 
    INTO   customerids 
    FROM   customers; 

    SELECT employeeno 
    INTO   employeeids 
    FROM   employees; 

    SELECT itemno 
    INTO   inventoryids 
    FROM   inventory; 

    f := utl_file.Fopen(ldir, lfile, 'R'); 

    LOOP 
        utl_file.Get_line(f, v_row); 
        v1 := Substr(v_row, 1, 4); 
        v2 := Substr(v_row, 6, 9); 
        v3 := Substr(v_row, 11, 12); 
        v4 := Substr(v_row, 15, 23); 
        v5 := Substr(v_row, 27, 35); 
        v6 := Substr(v_row, 38, 41); 
        v7 := Substr(v_row, 43); 
        v8 := Substr(v_row, 45, 48); 
        v9 := Substr(v_row, 50, 51); 
        IF v2 <> customerids THEN --checking customer id 
          RAISE customer_error; 
        ELSIF v3 <> employeeids THEN --checking employee id 
          RAISE employee_error; 
        ELSIF v6 <> inventoryids THEN --checking item1 id 
          RAISE item_error; 
        ELSIF v8 <> inventoryids THEN --checking item2 id 
          RAISE item_error; 
        ELSE 
          INSERT INTO transactions 
                      (tid, orderno,  cno,  employeeno,  received, 
                       shipped,  itemno1,  quantity1,  itemno2,  quantity2) 
          VALUES      (sequence_tid.NEXTVAL,  v1,  v2,  v3,  v4,  v5, 
                       v6,  v7,  v8,  v9); 
        END IF; 
    END LOOP; 

    result := TRUE; 

    RETURN result; 
EXCEPTION 
  WHEN customer_error THEN 
dbms_output.Put_line('Customer not found in parent Customer table'); WHEN 
employee_error THEN 
dbms_output.Put_line('Employee not found in Employee table'); 
                     WHEN item_error THEN 
dbms_output.Put_line('Item not found in inventory table'); WHEN OTHERS THEN 
dbms_output.Put_line('Error code:' 
                     || SQLCODE 
                     || '. Error Message: ' 
                     || SQLERRM); 

utl_file.Fclose(f); 

result := FALSE; 

RETURN result; 
END order_func; 

Вот как я назвал функцию (но я думаю, что это неправильно):

DECLARE
    results boolean;
BEGIN
    results := order_func('forQues','items.txt');
    DBMS_OUTPUT.PUT_LINE('Result for ORDER_FUNC Function is: ' || results);
END;

И это ошибка, которую я имею получил:

DECLARE
    results boolean;
BEGIN
    results := order_func('forQues','items.txt');
    DBMS_OUTPUT.PUT_LINE('Result for ORDER_FUNC Function is: ' || results);
END;
Error report -
ORA-06550: line 5, column 26:
PLS-00306: wrong number or types of arguments in call to '||'
ORA-06550: line 5, column 5:
PL/SQL: Statement ignored
06550. 00000 -  "line %s, column %s:\n%s"
*Cause:    Usually a PL/SQL compilation error.
*Action:

Я попытался удалить результаты в dbms_output и вот что получилось:

DECLARE
    results boolean;
BEGIN
    results := order_func('forQues','items.txt');
    DBMS_OUTPUT.PUT_LINE('Result for ORDER_FUNC Function is:');
END;

После запуска я получил:

Error code:-1422. Error Message: ORA-01422: exact fetch returns more than requested number of rows
Result for ORDER_FUNC Function is:


PL/SQL procedure successfully completed.

Пожалуйста, кто-нибудь помогите, как это исправить?

Ответы [ 2 ]

1 голос
/ 20 марта 2020

В дополнение к уже указанным ошибкам у вашей функции есть, по крайней мере, пара проблем. Я полагаю, что самой большой проблемой является ваше неправильное понимание функции Substring , в частности третьего параметра. Третий параметр опционально указывает желаемую длину , а не конечную позицию. Например, переменная v5 определена как дата, но значение установлено как «v5: = Substr (v_row, 27, 35);». У вас действительно есть дата длиной 35 символов. Кроме того, если третий параметр пропущен, результирующее значение распространяется от второго параметра до конца строки. Таким образом, v7 продолжается от позиции 43 до конца строки. V8, V9 - это числа, состоящие из 48 и 51 цифр соответственно, и каждое поле перекрывает следующее.

Другая большая проблема - ошибка NO_DATA_FOUND. У вас есть три места, где это может произойти (выбор), и 1, где это произойдет (utl_file.Get_line - вот как utl_file указывает на конец файла). Как структурировано, вы не можете знать, что послужило причиной этой ошибки. Далее я предлагаю метод решения этой проблемы. Я разбиваю каждый из этих элементов на собственную процедуру. Я оставляю проблему с подстрокой для вашего разрешения.

До этого немного философии. Имена и классификации важны. Имена должны описывать то, что представляют, но V1, V2 ... нет; так что вместо v5 возможно v_shipped_dt. Аналогичным образом объявление процедуры против функции должно быть сделано в зависимости от цели процедуры. Процедуры выполняются, функции получают вещи. Кажется, цель здесь состоит в том, чтобы загрузить данные, а не возвращать логическое значение. Поэтому я сделал это процедурой (она сообщает через выходной параметр). (Обычно я бы этого даже не сделал. Он успешно работает и ничего не возвращает или если не может вызвать исключение. Но это, возможно, стилист c.)

create or replace procedure load_order_file 
                          ( ldir  varchar2 
                          , lfile varchar2
                          , result out varchar2
                          ) 
as 
  customer_error exception; 
  employee_error exception; 
  item_error     exception; 

  f            utl_file.file_type; 
  v_row        varchar2(2000); 
  v1           number; 
  v2           number; 
  v3           number; 
  v4           date; 
  v5           date; 
  v6           number; 
  v7           number; 
  v8           number; 
  v9           number; 

  EOF_Reached Boolean ;   

  -- procedure to handle all file processing
  procedure load_order_buffer 
  is
  begin 
     if f is null or not util_file.is_open(f)
     then 
       f := utl_file.fopen(ldir, lfile, 'R'); 
       EOF_Reached := False;
     end if ; 

     utl_file.get_line(f, v_row);
  exception 
    when no_data_found then
      EOF_Reached := True;
      util_file.fclose(f);
  end load_order_buffer;  

  -- procedure to split file line into local variables
  procedure parse_buffer
  is 
  begin
    v1 := substr(v_row, 1, 4);   
    v2 := substr(v_row, 6, 9);   
    v3 := substr(v_row, 11, 12); 
    v4 := substr(v_row, 15, 23); 
    v5 := substr(v_row, 27, 35); 
    v6 := substr(v_row, 38, 41); 
    v7 := substr(v_row, 43);     
    v8 := substr(v_row, 45, 48); 
    v9 := substr(v_row, 50, 51); 
  end parse_buffer; 

  -- procedures to validate customer, employee, and inventory  
  procedure validate_customer(cust_no_in number)
  is 
     l_exists varchar2(1);
  begin 
     select null
       into l_exists 
       from customers
      where cno = cust_no_in; 
  exception 
    when no_data_found then
      raise customer_error;
  end validate_customer;

procedure validate_employee(employee_no_in number)
  is 
    l_exists varchar2(1);
  begin 
     select null
       into l_exists
       from employees
      where employeeno = employee_no_in; 
  exception 
    when no_data_found then
      raise employee_error;
  end validate_employee;  

procedure validate_inventory(inventory_no_in number)
  is 
    l_exists varchar2(1);
  begin 
     select null  
       into l_exists
       from inventory
      where itemno  = inventory_no_in; 
  exception 
    when no_data_found then
      raise item_error;
  end validate_inventory;  
-- Main 
begin 
    -- set up initial assumptions; 
    result := 'Failed'; 
    EOF_Reached := False; 

    loop 
      load_order_buffer;
      exit when EOF_Reached;

      parse_buffer; 
      validate_customer(v2);
      validate_employee(v3);
      validate_inventory(v6);
      validate_inventory(v8);

      -- everything valid create transaction  
      insert into transactions 
               (tid, orderno,  cno,  employeeno,  received, 
                shipped,  itemno1,  quantity1,  itemno2,  quantity2) 
        values (sequence_tid.nextval,  v1,  v2,  v3,  v4,  v5, 
                v6,  v7,  v8,  v9);  
    end loop; 
    result := 'Success';
exception 
  when customer_error then 
       dbms_output.put_line('Customer not found in parent Customer table');
  when employee_error then 
       dbms_output.put_line('Employee not found in Employee table'); 
  when item_error then 
       dbms_output.put_line('Item not found in inventory table');
  when others then 
       dbms_output.put_line('Error code:' 
                          || sqlcode 
                          || '. Error Message: ' 
                          || sqlerrm); 

end load_order_file ;
/

Вот тестовый драйвер

declare 
  result varchar2(8); 
begin
    load_order_file('forQues','items.txt');
    dbms_output.put_line('Load Order file terminated with ' || result);
    if result <> 'Success'
    then 
       rollback; 
    end if ; 
end ; 

Поскольку вы не предоставили ни таблицы DDL, ни данных образца, это не проверено . Удачи.

0 голосов
/ 20 марта 2020

Ошибка ORA-01422: exact fetch returns more than requested number of rows происходит, когда ваш запрос возвращает несколько строк, но у вас есть предложение INTO, которое ожидает, что будет возвращена только 1 строка.

Например, три ваших запроса:

select cno into customerids from customers;
select employeeno into employeeids from employees;
select itemno into inventoryids from inventory;

Ошибка PLS-00306: wrong number or types of arguments in call to '||' выдается, потому что вы пытаетесь объединить строку с логическим значением в

DBMS_OUTPUT.PUT_LINE('Result for ORDER_FUNC Function is: ' || results);, что не допускается.

Возможные исправления для ошибки ORA-01422: введите SELECT в FOR l oop, например:

FOR c IN (
    SELECT
        cno
    INTO customerids
    FROM
        customers
) LOOP
    --do stuff, access column value like c.cno
END LOOP;

Возможные исправления для ошибки PLS-00306 : Измените конкатенацию на

DBMS_OUTPUT.PUT_LINE('Result for ORDER_FUNC Function is: ' || case when results then 'true' else 'false' end);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...