简体   繁体   中英

Wrong number or types of arguments in call to '||'

We are supposed to read a text file, insert that data into a table while taking care of exceptions. This the code for my function:

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; 

This is how i've called the function (but i think it's wrong):

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

And this is the error I've got:

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:

I tried to remove the results in the dbms_output and this is what happened:

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

After running this i got:

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.

Please somebody help, how to fix this?

In addition to the errors already pointed out you function has a couple issues, at least. The biggest problem is, I believe, your misunderstanding of the Substring function, in particular the 3rd parameter. The 3rd parameter optionally indicated the length desired not the ending position. For example the variable v5 is defined as a date but the value is set as "v5 := Substr(v_row, 27, 35);". Do you really have a date that is 35 characters long. Additionally when the 3rd parameter is omitted then the resulting value extends from the 2nd parameter to the end of the string. So v7 extends from position 43 to the end of string. V8, V9 then are numbers that are 48 and 51 digits respectively and every field overlaps the one following.

The other big issue is the error NO_DATA_FOUND. You have three places where this is likely to occur (the selects) and 1 where it will occur (utl_file.Get_line - that's how utl_file indicates end-of-file). As structured you have no way of knowing which initiated that error. In the following I propose a method to resolve this issue. I break each of those element into a theit own procedure. I leave the substring issue for you to resolve.

Before that a little philosophy. Names and classifications are important. Names should describe what the represent but V1, V2 ... do not; so instead of v5 perhaps v_shipped_dt. Likewise declaring a procedure vs. function should done based on purpose of the routine. Procedures accomplish things, fuunctions get things. It seems the purpose here is to load data not return boolean. So I made it a procedure (it reports back via an out parameter). (Normally I wouldn't even do that. It runs successfully and returns nothing or if fails raising an exception. But that's perhaps stylistic.)

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 ;
/

Here is a test driver

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 ; 

Since you provided neither table DDL nor sample data this is not tested . Good Luck.

Error ORA-01422: exact fetch returns more than requested number of rows happens when your query returns multiple rows but you have an INTO clause which only expects 1 row to be returned.

For example, your three queries:

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

Error PLS-00306: wrong number or types of arguments in call to '||' is thrown because you are trying to concatenate a string with a boolean at

DBMS_OUTPUT.PUT_LINE('Result for ORDER_FUNC Function is: ' || results); which is not allowed.

Possible fixes for ORA-01422 error: Put your SELECT in a FOR loop like:

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

Possible fixes for PLS-00306 error: Change the concatenation to

DBMS_OUTPUT.PUT_LINE('Result for ORDER_FUNC Function is: ' || case when results then 'true' else 'false' end);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM