count(*) cannot be selected in PL/SQL - oracle

DECLARE
rec_count integer default 0;
str varchar(100);
BEGIN
str := 'select count(*) into ' || rec_count ||' from emp_table';
EXECUTE IMMEDIATE (str);
dbms_output.put_line(rec_count);
END;
I cannot get count in rec_count valibale. I received ORA-00905 message.
I have to add these lines in my script so sql statment should be like this.
I would pass trip name to this script and it would return count of that table.
thanks in advance.

you must use like below
DECLARE
rec_count integer default 0;
str varchar(100);
BEGIN
str := 'select count(*) from emp_table';
EXECUTE IMMEDIATE str into rec_count;
dbms_output.put_line(rec_count);
END;
the into clause must be use after execute immediate. refer here http://docs.oracle.com/cd/B12037_01/appdev.101/b10807/13_elems017.htm for more information

The correct way is EXECUTE IMMEDIATE str into rec_count;. the INTO clause must be used while you do EXECUTE IMMEDIATE.
SQL> set serveroutput on
SQL> DECLARE
2 rec_count integer default 0;
3 str varchar(100);
4 BEGIN
5 str := 'select count(*) from emp';
6 EXECUTE IMMEDIATE str into rec_count;
7 dbms_output.put_line(rec_count);
8 END;
9 /
14
PL/SQL procedure successfully completed.
SQL>

Related

Is there any way to assign a select query to local variable in PL/SQL other than select into statement?

Is there any way to assign a select query to local variable in PL/SQL other than select into statement?. Because select into throwing null value exception if the select query returns null value. Thanks
It would be helpful to post your code, but here is an example that should show the behavior you need. Assume there is a table called courses_tbl:
declare
cnumber number := NULL;
CURSOR c1
IS
SELECT course_number
FROM courses_tbl
WHERE course_name = 'XYZ';
BEGIN
open c1;
fetch c1 into cnumber;
if c1%notfound then
-- Do something here if you care about not found.
cnumber := 999; -- whatever
end if;
you can read about cursor attributes here
Seems that you need to use the exception handling as follows:
... -- Your procedure other code
BEGIN
SELECT <COLUMN_NAME> INTO <YOUR_VARIABLE>
FROM .....
WHERE ....
EXCEPTION WHEN NO DATA FOUND THEN
<YOUR_VARIABLE> := NULL;
END;
... -- Your procedure other code
You can use EXECUTE IMMEDIATE...INTO...:
DECLARE
nCnumber NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT CNUMBER FROM COURSES_TBL WHERE CNUMBER = 1'
INTO nCnumber;
DBMS_OUTPUT.PUT_LINE('SELECT #1 : nCnumber = ' || nCnumber);
nCnumber := NULL;
BEGIN
EXECUTE IMMEDIATE 'SELECT CNUMBER FROM COURSES_TBL WHERE CNUMBER = 100'
INTO nCnumber;
DBMS_OUTPUT.PUT_LINE('SELECT #2 : nCnumber = ' || nCnumber);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('SELECT #2 : NO DATA FOUND');
END;
END;
db<>fiddle here
You've seen how to do it using a cursor or exception handling section (which is - in my opinion - the right way to do it). However, as we're discussing, here's yet another option - an aggregate function. It won't return NO_DATA_FOUND but NULL.
This is what you have now:
SQL> declare
2 l_job emp.job%type;
3 begin
4 select job
5 into l_job
6 from emp
7 where ename = 'Does not exist';
8 end;
9 /
declare
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 4
This is what you might do:
SQL> declare
2 l_job emp.job%type;
3 begin
4 select max(job)
5 into l_job
6 from emp
7 where ename = 'Does not exist';
8 end;
9 /
PL/SQL procedure successfully completed.
SQL>

how to pass a string variable to the where clause in dynamic sql

I have to deploy my sql script and for that I have defined variable in one file and the create script in another file.
File 1:
Define_Variable.sql
DEFINE hr_SCHEMA = hr;
File 2:
Createfile.sql
#Define_variable.sql
declare
v_str varchar2(3000);
lc_cnt number;
BEGIN
v_str :='select count(1) into l_cnt from dba_tab_cols where owner=''' || &hr_SCHEMA ||''' and TABLE_NAME=''employees''';
execute immediate v_str;
IF l_cnt = 0 then
-----perform some operations
end if;
end ;
/
I'm getting the following error.
ORA-06550 and PLS-00201: identifier 'hr' must be declared.
Here the value is getting substituted but how to write the value within quotes. Like my output should execute
select count(1) into l_cnt from dba_tab_cols where owner= 'hr' and TABLE_NAME='employees';
This is just an example of my big script, but the objective is how to substiture a string varible in a where query of a dynamic sql.
Alternatively, you can use the variable inside the SQL string, just remember to add the quotes where owner= ''&HR_schema''
set serveroutput on
define HR_schema = hr
declare
v_str varchar2(3000);
l_cnt number;
begin
--v_str := 'select count(1) from dba_tab_cols where owner=:owner and TABLE_NAME=''employees''';
v_str := 'select count(1) from dba_tab_cols where owner= ''&HR_schema'' and TABLE_NAME=''employees''';
execute immediate v_str into l_cnt ; --using '&HR_schema';
if l_cnt = 0
then
dbms_output.put_line(l_cnt);
-----perform some operations
end if;
end;
Its best to user bind variables and the using clause.
declare
v_str varchar2(3000);
lc_cnt number;
begin
v_str := 'select count(1) from dba_tab_cols where owner=:owner and TABLE_NAME=''employees''';
execute immediate v_str into l_cnt using '&HR_schema';
if l_cnt = 0
then
-----perform some operations
end if;
end;

Oracle: Missing Expression

I have this set of code, it didn't return error when I compiled it.
create or replace PROCEDURE PARAM_CHECK
(
PARAM_CODE IN VARCHAR2,
TABLE_NAME IN VARCHAR2,
ISEXIST OUT INTEGER
)
IS
SQLSTMT VARCHAR2(200);
V_COUNT NUMBER;
BEGIN
SQLSTMT := 'SELECT COUNT(*) INTO '|| V_COUNT ||' FROM '|| TABLE_NAME ||' WHERE ID = '''||PARAM_CODE||''' AND ROWNUM = 1';
EXECUTE IMMEDIATE SQLSTMT;
COMMIT;
IF
V_COUNT = 0 THEN
ISEXIST := 0;
ELSE
ISEXIST := 1;
END IF;
END PARAM_CHECK;
But when after I try to run the procedure, it return this error:
Connecting to the database SAA.
ORA-00936: missing expression
ORA-06512: at "SAA.PARAM_CHECK", line 12
ORA-06512: at line 9
Process exited.
Disconnecting from the database SAA.
I have no idea why it return this error, plus when I compile everything is okay. I did search for the specific ORA error but didn't help much. Please help me. Thanks in advance.
Vcount is uninitialised at the time of the inclusion of its value into the sql statement so it produces a sytactically wrong blank at this position.
If it was feasible at all you'd have to write
SQLSTMT := 'SELECT COUNT(*) INTO V_COUNT FROM '|| TABLE_NAME ||' WHERE ID = '''||PARAM_CODE||''' AND ROWNUM = 1';
but this won't work either iirc since execute immediate opens a new scope.
You have to resort to
SQLSTMT := 'SELECT COUNT(*) FROM '|| TABLE_NAME ||' WHERE ID = '''||PARAM_CODE||''' AND ROWNUM = 1';
EXecute immediate sqlstmt into v_count;

How to output result of SELECT statement which is executed using native dynamic SQL?

I have a string which contains SQL SELECT statement.
I wonder how can I output result of the execution of that statement on the screen, execution will be done using native dynamic SQL (EXECUTE IMMEDIATE).
example:
DECLARE
v_stmt VARCHAR2 := 'SELECT * FROM employees';
BEGIN
EXECUTE IMMEDIATE v_stmt; -- ??? how to output result of that select on the screen.
END;
Important remark: structure of table can be any. I have to write a procedure which accepts name of the table as parameter, so I can't hardcode a table structure and don't want to do it.
Thanks for responses. Any ideas very appreciated/
If you are on Oracle 12c with a 12c client, this should work:
declare
rc sys_refcursor;
begin
open rc for 'select * from dual';
dbms_sql.return_result(rc);
end;
Yes we can execute select statement dynamically.
Let say we have a table test. It has four column Row_id,Name,Rank etc
When we do select * from test;
Result will be
Row_id Name Rank
1 R1 5
2 R2 1
3 R3 2
4 R4 4
Now we can use DBMS_SQL package to execute dynamically SELECT Sql Statament.
Code is below:
DECLARE
v_CursorID NUMBER;
v_table VARCHAR2(50):='test';
v_SelectRecords VARCHAR2(500);
v_NUMRows INTEGER;
v_MyNum INTEGER;
v_Myname VARCHAR2(50);
v_Rank INTEGER;
BEGIN
v_CursorID := DBMS_SQL.OPEN_CURSOR;
v_SelectRecords := 'SELECT * from ' || v_table ;
DBMS_SQL.PARSE(v_CursorID,v_SelectRecords,DBMS_SQL.V7);
DBMS_SQL.DEFINE_COLUMN(v_CursorID,1,v_MyNum);
DBMS_SQL.DEFINE_COLUMN(v_CursorID,2,v_Myname,50);
DBMS_SQL.DEFINE_COLUMN(v_CursorID,3,v_Rank);
v_NumRows := DBMS_SQL.EXECUTE(v_CursorID);
LOOP
IF DBMS_SQL.FETCH_ROWS(v_CursorID) = 0 THEN
EXIT;
END IF;
DBMS_SQL.COLUMN_VALUE(v_CursorId,1,v_MyNum);
DBMS_SQL.COLUMN_VALUE(v_CursorId,2,v_Myname);
DBMS_SQL.COLUMN_VALUE(v_CursorId,3,v_Rank);
DBMS_OUTPUT.PUT_LINE(v_MyNum || ' ' || v_Myname || ' ' || v_Rank );
END LOOP;
EXCEPTION
WHEN OTHERS THEN
RAISE;
DBMS_SQL.CLOSE_CURSOR(v_CursorID);
end;

using pl/sql to update sequences

We have a sql script to update a set of sequences after seed data populated our tables. The code below would not work:
declare
cursor c1 is
select
'select nvl(max(id),0) from '||uc.table_name sql_text,
uc.table_name||'_SEQ' sequence_name
from
user_constraints uc,
user_cons_columns ucc
where uc.constraint_type='P'
and ucc.constraint_name = uc.constraint_name
and ucc.column_name='ID'
and uc.owner='ME';
alter_sequence_text varchar2(1024);
TYPE generic_cursor_type IS REF CURSOR;
max_id number;
c2 generic_cursor_type;
begin
for r1 in c1 loop
open c2 for r1.sql_text;
fetch c2 into max_id;
close c2;
if( max_id != 0 ) then
dbms_output.put_line( 'seq name = '||r1.sequence_name );
execute immediate 'alter sequence '||r1.sequence_name||' increment by '||to_char(max_id);
dbms_output.put_line( 'max_id = '||to_char(max_id) );
execute immediate 'select '||r1.sequence_name||'.nextval from dual';
dbms_output.put_line( 'sequence value = '||to_char(next_id) );
execute immediate 'alter sequence '||r1.sequence_name||' increment by 1';
dbms_output.put_line( 'sequence: '||r1.sequence_name||' is at '||to_char(max_id+1) );
end if;
end loop;
end;
After searching I found a reference that stated I needed to change the line:
execute immediate 'select '||r1.sequence_name||'.nextval from dual'
and add 'into next_id;' (of course declaring next_id appropriately) so the result would be:
execute immediate 'select '||r1.sequence_name||'.nextval from dual into next_id;
I've only dealt lightly with pl/sql and sql in general and am interested to know why this change was necessary to make the script work correctly.
Thanks.
When you are using select inside PL/SQL block you have to place data returned by that select statement somewhere. So you have to declare a variable of appropriate data type and use select into clause to put data select returns into that variable even if select statement is executed by execute immediate statement.
Examples
declare
x number;
begin
select count(*)
into x
from all_objects;
end;
declare
x number;
begin
execute immediate 'select count(*)from all_objects' into x;
end;
So your execute immediate statement would be
execute immediate 'select '||sequence_name||'.nextval from dual' into newseqval;
If you are using Oracle 11g onward you can assign sequence's value directly to a variable, there is no need of using select into clause.
declare
x number;
begin
x := Sequence_Name.nextval;
end;
select seq_name.nextval from dual implies the implicit cursor creation and the results of the cursor should be fetched somewhere so you need fetch it into any externally declared bind variable.

Resources