Reputation: 486
I'm iterating through an array of table name strings and passing them to the following function:
FUNCTION table_empty(table_name VARCHAR2)
RETURN BOOLEAN
AS
row_count NUMBER := 0;
empty_sql VARCHAR2(255);
BEGIN
empty_sql := 'SELECT COUNT(1) FROM :tab_name';
EXECUTE IMMEDIATE empty_sql INTO row_count USING table_name;
DBMS_OUTPUT.PUT_LINE('Row Count: ' || table_name);
RETURN row_count > 0;
END table_empty;
However, I get this error
Unexpected error: ORA-00903: invalid table name
Does anybody have any idea what causes this?
Upvotes: 1
Views: 2053
Reputation: 21043
This is the preferred solution (avoiding the concatenation of the table_name as string) using the SQL Macro (requires Oracle 19.6 or higher)
In a SQL Macro you may pass safe a table name as a parameter.
Define (table) SQL Macro
create or replace function my_count (t DBMS_TF.Table_t)
return varchar2 SQL_MACRO
is
begin
return q'[
select count(*) cnt from t]';
end;
/
Usage for table TAB
select cnt from my_count(tab);
More information and examples of SQL Macros can be found here and there.
Upvotes: 3
Reputation: 934
You can do something like this and it will alleviate the need of a wrapper to pass in the table. You can add a where clause for filtering.
This make some time to complete if you have tables with a large amount of rows
declare
tab_count number(3);
sql_stmt varchar2(100);
BEGIN
FOR cur_Rec IN (Select TABLE_NAME from user_tables) LOOP
sql_stmt := 'SELECT count(*) FROM '|| cur_Rec.TABLE_NAME;
EXECUTE IMMEDIATE sql_stmt INTO tab_count ;
DBMS_OUTPUT.PUT_LINE (cur_Rec.TABLE_NAME || ' ' || tab_count);
END LOOP;
END;
Upvotes: 1
Reputation: 191235
Bind variables are for variables, not identifiers. The table name (and other identifiers) need to be known when the dynamic statement is parsed; variable values are then applied when it is executed. At the moment when the statement is parsed the table name is interpreted literally as :tab_name
, which is an invalid name.
You need to concatenate the name:
empty_sql := 'SELECT COUNT(1) FROM ' || table_name;
EXECUTE IMMEDIATE empty_sql INTO row_count;
You might want to validate the table name first though.
Upvotes: 4