Why a type cannot be constrained? - sql

I am struggling with the following code:
DECLARE
TOTACID TAB_OF_ID(50);
RES NUMBER;
BEGIN
SELECT DISTINCT ID INTO TOTACID
FROM TABLE_B;
FOR indx IN 1 .. TOTACID.COUNT
LOOP
RES := F_IMPORT(TOTACID(indx));
DBMS_OUTPUT.PUT_LINE ('Moved ID ' || RES);
END LOOP;
END;
/
When I run it, it fails with the error:
Error report -
ORA-06550: line 2, column 11:
PLS-00566: type name "TAB_OF_ID" cannot be constrained
ORA-06550: line 5, column 19:
PL/SQL: ORA-00932: inconsistent datatypes: expected UDT got NUMBER
ORA-06550: line 5, column 3:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Where TAB_OF_ID has been declared as follows:
create or replace TYPE TAB_OF_ID AS table of NUMBER(19,2);
I don't understand what is wrong. It seems that I cannot declare TOTACID TAB_OF_ID(50) but in a function I created some days ago I could declare LIS_ID TAB_OF_ID := TAB_OF_ID(50); and it works properly.
What is the difference with the script I have here?

Obviously TOTACID TAB_OF_ID(50) is different to LIS_ID TAB_OF_ID := TAB_OF_ID(50); The command is like
{variable name} {data type} := {inital value};
where := {inital value} is optional.
TOTACID TAB_OF_ID(50) would mean
{variable name} {inital value};
which is not valid syntax.

You can not declare the variable by assigning your table a fixed number of records, so you need something like:
DECLARE
TOTACID TAB_OF_ID;
RES NUMBER;
BEGIN
SELECT DISTINCT ID bulk collect INTO TOTACID
FROM TABLE_B;
...
END;
/
Also, notice that you are fetching more than one value, so you need BULK COLLECT INTO.
About
LIS_ID TAB_OF_ID := TAB_OF_ID(50);
here you are not declaring a variable with a given number of records, but you are assigning to a variable the 50th value of the table.

Related

how to insert only one column values from one table to another using pl/sql block?

my code is not working when i run it while inserting values from one table to another table.why this code is not working when insert into statement is right. please refer the table desc is same for both table.
table- desc site_sector
----------- ----- ------------
CIRCLE_NAME VARCHAR2(50)
REF_MONTH VARCHAR2(50)
REF_YEAR VARCHAR2(50)
declare
type t_list is table of varchar2(50);
v_array t_list:=t_list();
begin
select circle_name bulk collect into v_array from all_sector;
for i in 1..10 loop
dbms_output.put_line(v_array(i));
insert into site_sector(circle_name) values v_array(i);
end loop;
end;
########################################
Error report -
ORA-06550: line 8, column 25:
PL/SQL: ORA-03001: unimplemented feature
ORA-06550: line 8, column 1:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilati
on error.
2) This code is also not working
declare
type t_list is varray(5) of varchar2(50);
v_array t_list;
begin
v_array:=t_list('PB','OR','TN','RJ');
for i in 1..v_array.count loop
dbms_output.put_line(v_array(i));
insert into site_sector (circle_name) values v_array(i);
end loop;
end;
############################################################
Error report -
ORA-06550: line 8, column 26:
PL/SQL: ORA-03001: unimplemented feature
ORA-06550: line 8, column 1:
PL/SQL: SQL Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
You are not using the proper syntax for an Oracle insert statement.
insert into site_sector (circle_name) values v_array(i) ;
should be
insert into site_sector (circle_name) values ( v_array(i) ) ;
You should become familiar with the PL/SQL FORALL statement.

Error in returning record from function in Oracle PL/SQL

DECLARE
TYPE type_supplier IS
RECORD(supp_phone supplier.supplier_phone%TYPE,
supp_status supplier.supplier_status%TYPE);
FUNCTION fn_supplier(supp_name supplier.supplier_name%TYPE)
RETURN type_supplier
IS supp type_supplier;
BEGIN
select supplier_phone, supplier_status
into supp.supp_phone, supp.supp_status
from supplier
where supplier_name = supp_name;
RETURN supp;
END;
The question is: Create a function that returns Phone Number and status for inputted supplier name. Supplier table has supplier_id, supplier_name, supplier_address, supplier_email, supplier_phone, supplier_status.
I am getting error in above code as:
Error report -
ORA-06550: line 16, column 4:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
begin function pragma procedure
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
I don't know hoe to return multiple values from PL/SQL function. I'm using record type for that but getting the error.
I am open for any solution, changes or alternative methods..
Your declaration of the TYPE is not correct.
You can use the OBJECT type and use it as follows:
create TYPE type_supplier IS
OBJECT(supp_phone supplier.supplier_phone%TYPE,
supp_status supplier.supplier_status%TYPE);
/
FUNCTION fn_supplier(supp_name supplier.supplier_name%TYPE)
RETURN type_supplier
IS supp type_supplier;
BEGIN
select supplier_phone, supplier_status
into supp.supp_phone, supp.supp_status
from supplier
where supplier_name = supp_name;
RETURN supp;
END;
/
In PL/SQL what's commonly done is to return an opened cursor which the caller can then walk through. For example:
FUNCTION fn_supplier(supp_name supplier.supplier_name%TYPE)
RETURN SYS_REFCURSOR
IS
csr SYS_REFCURSOR
BEGIN
OPEN csr FOR
SELECT SUPPLIER_PHONE, SUPPLIER_STATUS
FROM SUPPLIER
WHERE SUPPLIER_NAME = pinSupplier_name;
RETURN csr;
END fn_supplier;
Then the caller of the function looks something like:
DECLARE
csrSupplier SYS_REFCURSOR;
vSupplier_phone SUPPLIER.SUPPLIER_PHONE%TYPE;
vSupplier_status SUPPLIER.SUPPLIER_STATUS%TYPE;
BEGIN -- some anonymous
csrSupplier := fn_supplier('Cthulhu, Inc.'); -- why deal with the lesser evil?
LOOP
FETCH csrSupplier INTO vSupplier_phone, vSupplier_status;
EXIT WHEN cv%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Phone=' || vSupplier_phone ||
' Status=' || vSupplier_status);
END LOOP;
CLOSE csrSupplier;
END;

How to fix strange oracle PL/SQL error - "PLS-00049: bad bind variable"

I am trying to write an execute an oracle PL/SQL function that return the number of records within a table, where one of the fields matches a certain name.
Here is my code:
create or replace function getNum
return number
as
v_x number;
begin
SELECT COUNT(*) INTO :v_x
FROM UserResponses WHERE NHSPlatform_Name = 'Improvement Data and Analytics';
return v_x;
end;
/
execute getNum();
I keep getting strange errors:
Function GETNUM compiled
LINE/COL ERROR
--------- ------------------------------------------------------------- 6/22 PLS-00049: bad bind variable 'V_X' Errors: check compiler log
Error starting at line : 85 in command - BEGIN getNum(); END; Error
report - ORA-06550: line 1, column 7: PLS-00905: object
B7011343.GETNUM is invalid ORA-06550: line 1, column 7: PL/SQL:
Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
First thing is to correct your function as pmdba wrote in his answer.
This would then be a correct function:
create or replace function getNum
return number
as
v_x number;
begin
SELECT COUNT(*) INTO v_x
FROM UserResponses WHERE NHSPlatform_Name = 'Improvement Data and Analytics';
return v_x;
end;
/
Then you need to call your function in correct way. This is one way of calling it:
select getNum from dual;
here is a small demo
Drop the ":" from the select statement:
create or replace function getNum
return number
as
v_x number;
begin
SELECT COUNT(*) INTO v_x
FROM UserResponses WHERE NHSPlatform_Name = 'Improvement Data and Analytics';
return v_x;
end;
/
select getNum() from dual;
Try this:
SQL> VARIABLE ret_val NUMBER;
SQL> execute :ret_val := getnum;
PL/SQL procedure successfully completed.
SQL> select :ret_val from dual;

How do I convert this procedure to a PLSQL block correctly ? Reference to uninitialized function

The following block compiles correctly .(Unimportant parts redacted)
CREATE OR REPLACE PROCEDURE testProc
IS
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
test_h_list test_h;
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids;
BEGIN
test_h_list('A'):='Apple';
test:=test_h_list.FIRST;
WHILE test IS NOT NULL LOOP
BEGIN
SELECT tbl1.l_id BULK COLLECT INTO l_id_list
WHERE ....
....
....
END;
However, when I attempt to convert it into a plsql block
DECLARE
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
test_h_list test_h; --ORA-06531: Reference to uninitialized collection :-(
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids;
BEGIN
test_h_list('A'):='Apple';
test:=test_h_list.FIRST;
WHILE test IS NOT NULL LOOP
BEGIN
SELECT tbl1.l_id BULK COLLECT INTO l_id_list
WHERE ....
....
....
END;
I get the 'ORA-06531: Reference to uninitialized collection ' error as annotated above. I tried searching around and came across this and based on the examples here
I came up with this
DECLARE
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
test_h_list test_h := test_h();
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids :=l_ids();
BEGIN
test_h_list.EXTEND(100);
l_ids.EXTEND(100);
test_h_list('A'):='Apple';
test:=test_h_list.FIRST;
WHILE test IS NOT NULL LOOP
BEGIN
SELECT tbl1.l_id BULK COLLECT INTO l_id_list
WHERE ....
....
....
END;
But this throws an error saying PLS-00222: no function with name 'test_h' exists in this scope. Any idea on what I might be missing?
MCVE
Script -
DECLARE
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
test_h_list test_h := test_h(); --Line 3
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids := l_ids();
test_str VARCHAR(50);
BEGIN
test_h_list.EXTEND(100);
l_id_list.EXTEND(100);
test_h_list('App'):='1';
test_h_list('Red'):='2';
test_str:=test_h_list.FIRST;
WHILE test_str IS NOT NULL LOOP
BEGIN
SELECT TABLE1.DEPT BULK COLLECT INTO l_id_list
FROM TABLE1
WHERE TABLE1.NAME = test_str;
FOR indx IN 1..l_id_list.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE( l_id_list(indx));
END LOOP;
test_str:=test_h_list.NEXT(test_str);
EXCEPTION
WHEN OTHERS THEN -- Just print the failure to logs
NULL;
END;
END LOOP;
END;
/
Error Report -
Error starting at line 1 in command:
DECLARE
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
test_h_list test_h := test_h();
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids := l_ids();
test_str VARCHAR(50);
BEGIN
test_h_list.EXTEND(100);
l_id_list.EXTEND(100);
test_h_list('App'):='1';
test_h_list('Red'):='2';
test_str:=test_h_list.FIRST;
WHILE test_str IS NOT NULL LOOP
BEGIN
SELECT TABLE1.DEPT BULK COLLECT INTO l_id_list
FROM TABLE1
WHERE TABLE1.NAME = test_str;
FOR indx IN 1..l_id_list.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE( l_id_list(indx));
END LOOP;
test_str:=test_h_list.NEXT(test_str);
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
END LOOP;
END;
Error report:
ORA-06550: line 3, column 23:
PLS-00222: no function with name 'TEST_H' exists in this scope
ORA-06550: line 3, column 13:
PL/SQL: Item ignored
ORA-06550: line 9, column 3:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 9, column 3:
PL/SQL: Statement ignored
ORA-06550: line 11, column 3:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 11, column 3:
PL/SQL: Statement ignored
ORA-06550: line 12, column 3:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 12, column 3:
PL/SQL: Statement ignored
ORA-06550: line 13, column 13:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 13, column 3:
PL/SQL: Statement ignored
ORA-06550: line 27, column 15:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 27, column 5:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Elapsed: 00:00:00.011
In your MCVE you're mixing up different types of PL/SQL table. Your test_h types is indexed so doesn't need to be initialized and can't be extended - since it's a sparse table type. So removing the := test_h() and the extend line makes this work:
DECLARE
TYPE test_h IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);
test_h_list test_h; -- do no instantiate := test_h(); --Line 3
TYPE l_ids IS TABLE OF VARCHAR(100);
l_id_list l_ids := l_ids();
test_str VARCHAR(50);
BEGIN
-- test_h_list.EXTEND(100); -- do not extend either
l_id_list.EXTEND(100);
test_h_list('App'):='1';
test_h_list('Red'):='2';
test_str:=test_h_list.FIRST;
WHILE test_str IS NOT NULL LOOP
BEGIN
SELECT TABLE1.DEPT BULK COLLECT INTO l_id_list
FROM TABLE1
WHERE TABLE1.NAME = test_str;
FOR indx IN 1..l_id_list.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE( l_id_list(indx));
END LOOP;
test_str:=test_h_list.NEXT(test_str);
EXCEPTION
WHEN OTHERS THEN -- Just print the failure to logs
NULL;
END;
END LOOP;
END;
/
PL/SQL procedure successfully completed.
Your original first anonymous block wasn't doing either of those things, and had the same sparse table type for test_h, so should not have been getting the ORA-06531. You would have seen it if you'd removed the INDEX BY VARCHAR2(100) from the type definition, but that isn't what you showed.
You could also have got it from trying to refer to elements of l_id_list without initialising that - but as presented in the question, it would always have been initalized implicitly by the bulk collect in the loop, even if the real table being queried was empty - you'd just have an empty PL/SQL table.
The code you originally showed doesn't throw the error; and the MCVE is doing something different, closer to your second anonymous block than the first one.

dbms_output cannot print boolean?

I am learning cursors and I cannot print the boolean value in the
dbms_output.put_line();
The code is
DECLARE
CURSOR c_employees_3i is
SELECT * FROM employees_3i;
row_count BOOLEAN;
BEGIN
OPEN c_employees_3i;
row_count := c_employees_3i%isopen;
Dbms_Output.put_line(bool_to_text(row_count));
CLOSE c_employees_3i;
END;
I get this error
ORA-06550: line 8, column 22:
PLS-00201: identifier 'BOOL_TO_TEXT' must be declared
ORA-06550: line 8, column 1:
PL/SQL: Statement ignored
Please help me to rectify the error. Thanks
The function bool_to_text does not exist (and AFAIK, Oracle never had such a function).
You can use diutil.bool_to_int to convert the Boolean to an Integer and print that:
begin
dbms_output.put_line(sys.diutil.bool_to_int(true));
end;