How do I test if a column equals empty_clob() in Oracle? - oracle

The naïve FOO = empty_clob() complains about incompatible types. I tried Googling, but (once again) had little success searching for help with Oracle. Thanks.

Are you just wanting to check for a CLOB that doesn't have any length? While not exactly what your asking, it's basically the same thing?
select *
from bar
where dbms_lob.getlength(foo) = 0;
Here is the complete test:
SQL> create table bar (foo clob);
Table created.
SQL> insert into bar values (empty_clob());
1 row created.
SQL> select *
2 from bar
3 where dbms_lob.getlength(foo) = 0;
FOO
--------------------------------------------------------------------------------

If you are trying to do the comparison in PL/SQL, you can just test equality as Igor's solution does
SQL> ed
Wrote file afiedt.buf
1 DECLARE
2 dummy clob;
3 BEGIN
4 dummy := empty_clob();
5 IF dummy = empty_clob() THEN
6 dbms_output.put_line( 'Dummy is empty' );
7 ELSE
8 dbms_output.put_line( 'Dummy is not empty' );
9 END IF;
10* END;
SQL> /
Dummy is empty
PL/SQL procedure successfully completed.
If you are trying to do this in SQL, thougyh, you need to use the DBMS_LOB.COMPARE function. A LOB column in a table is really a LOB locator (i.e. pointer), so what you really care about is that the value pointed to by the LOB is comparable to the value pointed to by the LOB locator returned by the EMPTY_CLOB() function.
SQL> desc bar
Name Null? Type
----------------------------------------- -------- ------------------------
FOO CLOB
SQL> insert into bar values ('123');
1 row created.
SQL> insert into bar values( empty_clob() );
1 row created.
SQL> insert into bar values( empty_clob() );
1 row created.
SQL> ed
Wrote file afiedt.buf
1 select count(*)
2 from bar
3* where dbms_lob.compare( foo, empty_clob() ) = 0
SQL> /
COUNT(*)
----------
2
SQL> ed
Wrote file afiedt.buf
1 select count(*)
2 from bar
3* where dbms_lob.compare( foo, empty_clob() ) != 0
SQL> /
COUNT(*)
----------
1

something like this should work for initialization:
DECLARE
dummy clob;
dummy2 clob;
BEGIN
dummy := empty_clob();
IF dummy = empty_clob() THEN
dummy2 := dummy;
END IF;
END;

A simple way to test for empty clobs in SQLplus is to convert all the CLOBS to varchar2 (using the TO_CHAR function) before performing the test:
SELECT *
FROM table1
WHERE TO_CHAR(table1.column1) IS NULL

DECLARE
dummy CLOB := 'fxsgf';
dummy1 CLOB;
BEGIN
IF dummy1 = EMPTY_CLOB ()
THEN
DBMS_OUTPUT.put_line ('Dummy1 is empty');
ELSE
DBMS_OUTPUT.put_line ('Dummy1 is not empty');
END IF;
IF dummy = EMPTY_CLOB ()
THEN
DBMS_OUTPUT.put_line ('Dummy is empty');
ELSE
DBMS_OUTPUT.put_line ('Dummy is not empty');
END IF;
END;

Related

TABLE OF VARCHAR2 in WHERE clause

The code is simplified. I have a type:
CREATE TYPE str_tab_t IS TABLE OF VARCHAR2(20);
Here a function:
FUNCTION MYFUNCTION(myVar IN str_tab_t ) RETURN VARCHAR
myVar2 NUMBER;
BEGIN
SELECT MYCOLUMN INTO myVar2 FROM MYTABLE WHERE MYCOLUMN IN(SELECT * FROM myVar );
RETURN myVar2 ;
END MYFUNCTION;
I wonder if it possible to call the function like this:
MYFUNCTION(str_tab_t ('abc'));
As I'm getting error ORA-01722. I don't think, that it is because of wrong query. I think, I'm passing the argument in a wrong way. Could someone give me any clue? Thanks!
Did you by any chance OVERsimplified it?
Because, if table contents is something like this (i.e. strings in MYCOLUMN)
SQL> select * from mytable;
MYC
---
abc
def
and you want the function to return a number, then you can't select mycolumn (which is a string) into a number datatype local function variable myvar2. But, you can select some number (such as 1 in my example):
SQL> create or replace function myfunction (myvar in str_tab_t)
2 return number
3 is
4 myvar2 number;
5 begin
6 select 1 into myvar2
7 from mytable
8 where mycolumn in (select * from table(myvar));
9 return myvar2;
10 end;
11 /
Function created.
SQL> select myfunction(str_tab_t('abc')) from dual;
MYFUNCTION(STR_TAB_T('ABC'))
----------------------------
1
SQL>
Or, obviously, return a different datatype:
SQL> create or replace function myfunction (myvar in str_tab_t)
2 return mytable.mycolumn%type
3 is
4 myvar2 mytable.mycolumn%type;
5 begin
6 select mycolumn into myvar2
7 from mytable
8 where mycolumn in (select * from table(myvar));
9 return myvar2;
10 end;
11 /
Function created.
SQL> select myfunction(str_tab_t('abc')) from dual;
MYFUNCTION(STR_TAB_T('ABC'))
-------------------------------------------------------------------------
abc
SQL>

How to write PL/SQL function which returns the result of a select statement having as pararmeters the function's parameters?

I tried to write a PL/SQL function having as parameters a tablename and a column name, which returns the result of the query as a table.
Here's what I tried:
CREATE TYPE TABLE_RES_OBJ AS OBJECT (
employee_id number(30) ,
person_id number(30),
joined_year number(4),
salary number(20,2),
qualification varchar2(45),
department varchar2(45)
);
/
create TYPE table_ret as TABLE OF table_res_obj;
/
create or replace function select_custom(p_tablename varchar2, p_colname varchar2 ) return table_ret
is
ret table_ret;
query_txt varchar2(100) := 'SELECT :a from :b';
begin
execute immediate query_txt bulk collect into ret using p_colname, p_tablename;
return ret;
end select_custom;
As you can see, this is not that general as wanted, but still not working, it says the table doesn't exist, even when I try to run it with an existing table.
Exactly, it won't work that way. You'll have to concatenate table and column name into the select statement. For (simple) example:
SQL> create or replace type table_res_obj as object
2 (ename varchar2(20));
3 /
Type created.
SQL> create or replace type table_ret as table of table_res_obj;
2 /
Type created.
SQL> create or replace function select_custom
2 (p_tablename varchar2, p_colname varchar2 )
3 return table_ret
4 is
5 ret table_ret;
6 query_txt varchar2(100);
7 begin
8 query_txt := 'select table_res_obj(' || dbms_assert.simple_sql_name(p_colname) ||') from ' ||
9 dbms_assert.sql_object_name(p_tablename);
10 execute immediate query_txt bulk collect into ret;
11 return ret;
12 end select_custom;
13 /
Function created.
Does it work?
SQL> select select_custom('dept', 'deptno') from dual;
SELECT_CUSTOM('DEPT','DEPTNO')(ENAME)
--------------------------------------------------------------------------------
TABLE_RET(TABLE_RES_OBJ('10'), TABLE_RES_OBJ('20'), TABLE_RES_OBJ('30'), TABLE_R
ES_OBJ('40'))
SQL>

How to pass string of comma-separated numbers to stored procedure in condition for numeric field?

I have a stored procedure like below where multiple employee IDs will be passed as comma-separated value (multiple IDs). It is throwing error as "ORA-01722: invalid number". I know it's because of passing varchar2 variable for the numeric ID column. But is there any way we can achieve this simply?
create or replace PROCEDURE Fetch_Emp_Name(Emp_id in varchar2)
IS
BEGIN
select Name from EMP where id in (emp_id);
END;
You can use dynamic sql.
create or replace PROCEDURE Fetch_Emp_Name(emp_id in varchar2) IS
v_result varchar2;
begin
execute immediate
'select Name from EMP where id in (' || 'emp_id' || ')'
into
v_result;
end;
Also you can use package dbms_sql for dynamic sql.
Update
Another approach. I think may be better.
create or replace PROCEDURE Fetch_Emp_Name(emp_id in varchar2) IS
v_result varchar2;
begin
select
Name
from
EMP
where
id in
(
select
to_number(regexp_substr(emp_id, '[^,]+', 1, level))
from
dual
connect by regexp_substr(emp_id, '[^,]+', 1, level) is not null
);
exception
when no_data_found then
-- error1;
when too_many_rows then
-- error2;
end;
Sorry for before, I did not get the question in the right way. If you get a lot of IDs as different parameters, you could retrieve the list of names as an string split by comma as well. I put this code where I handled by regexp_substr the name of different emp_ids you might enter in the input parameter.
Example ( I am assuming that the IDs are split by comma )
create or replace PROCEDURE Fetch_Emp_Name(p_empid in varchar2) IS
v_result varchar2(4000);
v_append emp.name%type;
v_emp emp.emp_id%type;
counter pls_integer;
i pls_integer;
begin
-- loop over the ids
counter := REGEXP_COUNT(p_empid ,'[,]') ;
--dbms_output.put_line(p_empid);
if counter > 0
then
i := 0;
for r in ( SELECT to_number(regexp_substr(p_empid,'[^,]+',1,level)) as mycol FROM dual CONNECT BY LEVEL <= REGEXP_COUNT(p_empid ,'[,]')+1 )
loop
--dbms_output.put_line(r.mycol);
v_emp := r.mycol ;
select name into v_append from emp where emp_id = v_emp;
if i < 1
then
v_result := v_append ;
else
v_result := v_result ||','|| v_append ;
end if;
i := i + 1;
end loop;
else
v_emp := to_number(p_empid);
select name into v_result from emp where emp_id = v_emp;
end if;
dbms_output.put_line(v_result);
exception
when no_data_found
then
raise_application_error(-20001,'Not Employee found for '||v_emp||' ');
when too_many_rows
then
raise_application_error(-20002,'Too many employees for id '||v_emp||' ');
end;
Test
SQL> create table emp ( emp_id number, name varchar2(2) ) ;
Table created.
SQL> insert into emp values ( 1 , 'AA' );
1 row created.
SQL> insert into emp values ( 2 , 'BB' ) ;
1 row created.
SQL> commit;
SQL> insert into emp values ( 3 , 'CC' ) ;
1 row created.
SQL> select * from emp ;
EMP_ID NA
---------- --
1 AA
2 BB
3 CC
SQL> exec Fetch_Emp_Name('1') ;
AA
PL/SQL procedure successfully completed.
SQL> exec Fetch_Emp_Name('1,2,3') ;
AA,BB,CC
PL/SQL procedure successfully completed.
SQL>

fetching table data into a table using cursor

I have a table called phonebook and it has two columns (firstName, LastName). I want to create a table of lastName index by firstName using cursor, and I wrote this code:
CREATE OR REPLACE PROCEDURE proc1 AS
TYPE tableNames IS TABLE OF VARCHAR2(20) INDEX BY VARCHAR(20);
v1 tableNames;
v_firstName PHONEBOOK.FIRSTNAME%TYPE;
v_lastName PHONEBOOK.LASTNAME%TYPE;
CURSOR c_name IS SELECT FIRSTNAME, LASTNAME FROM PHONEBOOK;
BEGIN
OPEN c_name;
LOOP
FETCH c_name INTO v_firstName, v_lastName;
EXIT WHEN c_name%NOTFOUND;
v1(v_firstName) := v_lastName;
END LOOP;
FOR idx IN v1.FIRST..v1.LAST
LOOP
DBMS_OUTPUT.PUT_LINE (v1(idx));
END LOOP;
CLOSE c_name;
END;
/
It has been successfully compiled. When I run this procedure it should print lastNames which stored in the tableNames but it gave me an error:
ORA-06502 "PL/SQL: numeric or value error"
Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
Please help me to solve this problem
Not FOR, but WHILE. Also, I used cursor FOR loop as a source; easier to write & maintain.
SQL> create table phonebook (firstname varchar2(10), lastname varchar2(10));
Table created.
SQL> insert into phonebook
2 select 'Little', 'Foot' from dual union all
3 select 'Mc' , 'Donalds' from dual;
2 rows created.
SQL> create or replace procedure proc1 as
2 type tablenames is table of varchar2(10) index by varchar2(10);
3 v1 tablenames;
4 idx varchar2(10);
5 begin
6 for cur_r in (select firstname, lastname
7 from phonebook
8 )
9 loop
10 v1(cur_r.firstname) := cur_r.lastname;
11 end loop;
12
13 idx := v1.first;
14 while idx is not null loop
15 dbms_output.put_line(v1(idx));
16 idx := v1.next(idx);
17 end loop;
18 end;
19 /
Procedure created.
SQL> exec proc1;
Foot
Donalds
PL/SQL procedure successfully completed.
SQL>

using cursor attributes in a CURSOR FOR LOOP

I am running the following in the Scott schema:
SET serveroutput ON;
BEGIN
FOR c_Emp IN (SELECT * FROM emp)
LOOP
dbms_output.put_line('The record processed by the cursor ' || c_Emp%rowcount);
END LOOP;
end;
This gives the error:
cursor attribute may not be applied to non-cursor 'C_EMP'
However if this is done using an explicit cursor it works fine:
set serveroutput on ;
DECLARE
emp_record emp%ROWTYPE;
count_variable NUMBER;
CURSOR c IS
SELECT * FROM emp;
BEGIN
OPEN c;
loop
fetch c INTO emp_record;
exit WHEN c%notfound;
dbms_output.put_line ('The record count is ' || c%rowcount);
END loop;
close c;
end;
Just want to understand : whether while using the CURSOR FOR LOOP, is the index variable not a cursor attribute, if so why? could someone plz expalin this....
c_Emp is not the cursor, its a record with felds for each column in the SELECT statment
c_Emp is similar to the emp_record from your second example.
Even while using a FOR loop the cursor has to be explicitly defined.
A sample use of FOR loop with a cursor would look like below:
declare
cursor c1 is select a from table;
begin
FOR b in c1
loop
<required logic>
end loop;
end;
To get the index in a for loop, you can add the rownum pseudocolumn in the select clause of implicit cursor.
SET serveroutput ON;
BEGIN
FOR c_Emp IN (SELECT e.*, rownum FROM emp e)
LOOP
dbms_output.put_line('The record processed by the cursor ' || c_Emp.rownum);
END LOOP;
end;
Try this:
SET serveroutput ON;
DECLARE
x NUMBER :=0 ;
BEGIN
FOR c_Emp IN (SELECT * FROM emp)
LOOP
x := x+1;
dbms_output.put_line('The record processed by the cursor ' || x);
END LOOP;
-----
IF x>0 THEN
dbms_output.put_line('Cursr was opened');
ELSE
dbms_output.put_line('Cursr was not opened');
END IF;
end;
SQL> create table product(
2 product_id number(4) not null,
3 product_description varchar2(20) not null
4 );
Table created.
SQL>
SQL> insert into product values (1,'Java');
1 row created.
SQL> insert into product values (2,'Oracle');
1 row created.
SQL> insert into product values (3,'C#');
1 row created.
SQL> insert into product values (4,'Javascript');
1 row created.
SQL> insert into product values (5,'Python');
1 row created.
SQL> create table company(
2 product_id number(4) not null,
3 company_id NUMBER(8) not null,
4 company_short_name varchar2(30) not null,
5 company_long_name varchar2(60)
6 );
Table created.
SQL> insert into company values(1,1001,'A Inc.','Long Name A Inc.');
1 row created.
SQL> insert into company values(1,1002,'B Inc.','Long Name B Inc.');
1 row created.
SQL> insert into company values(1,1003,'C Inc.','Long Name C Inc.');
1 row created.
SQL> insert into company values(2,1004,'D Inc.','Long Name D Inc.');
1 row created.
SQL> insert into company values(2,1005,'E Inc.','Long Name E Inc.');
1 row created.
SQL> insert into company values(2,1006,'F Inc.','Long Name F Inc.');
1 row created.
SQL> DECLARE
2 CURSOR cursorValue IS
3 SELECT h.product_description,o.company_short_name FROM company o,product h
4 WHERE o.product_id =h.product_id
5 ORDER by 2;
6 num_total_rows NUMBER;
7 BEGIN
8
9 FOR idx IN cursorValue LOOP
10 dbms_output.put_line(rpad(idx.product_description,20,' ')||' '||
11 rpad(idx.company_short_name,30,' '));
12
13 num_total_rows :=cursorValue%ROWCOUNT;
14 END LOOP;
15 IF num_total_rows >0 THEN
16 dbms_output.new_line;
17 dbms_output.put_line('Total Organizations = '||to_char(num_total_rows));
18 END IF;
19 END;
20 /
Java A Inc.
Java B Inc.
Java C Inc.
Oracle D Inc.
Oracle E Inc.
Oracle F Inc.
Total Organizations = 6
PL/SQL procedure successfully completed.
SQL> drop table product;
Table dropped.
SQL> drop table company;
Table dropped.
enter code here

Resources