How to use dynamic where clause in EXECUTE IMMEDIATE - sql

I have a table with columns insert,select,where clause,dynamic where clause,group by clause.
Using procedure i need to execute insert into statement and also use dynamic where clause.
I tried the following one however it is giving me an error missing expression.
create or replace PROCEDURE dynamicWhereClause(Datee IN DATE,processId IN NUMBER)
IS
processName VARCHAR2(100);
tablePrefix CONFIG_DETAILS.SOURCE_TABLE%Type;
sourceTableType CONFIG_DETAILS.SOURCE_TABLE_TYPE%Type;
insertClause CONFIG_DETAILS.INSERT_CLAUSE%Type;
selectClause CONFIG_DETAILS.SELECT_CLAUSE%Type;
whereClause CONFIG_DETAILS.WHERE_CLAUSE%Type;
onUpdateClause CONFIG_DETAILS.ON_UPDATE_CLAUSE%Type;
groupByClause CONFIG_DETAILS.GROUP_BY_CLAUSE%Type;
orderByClause CONFIG_DETAILS.ORDER_BY_CLAUSE%Type;
isDynamicWhereClause CONFIG_DETAILS.IS_DYNAMIC_WHERE_CLAUSE%Type;
tableName VARCHAR2(50);
Process_Date DATE;
processQuery VARCHAR2(6000 BYTE);
CURSOR Process_Report IS
select NAME,SOURCE_TABLE,SOURCE_TABLE_TYPE,INSERT_CLAUSE,SELECT_CLAUSE,WHERE_CLAUSE,ON_UPDATE_CLAUSE,GROUP_BY_CLAUSE,ORDER_BY_CLAUSE,IS_DYNAMIC_WHERE_CLAUSE FROM
CONFIG_DETAILS where ID=processId;
BEGIN
OPEN Process_Report;
LOOP
FETCH Process_Report INTO processName,tablePrefix,sourceTableType,insertClause,selectClause,whereClause,onUpdateClause,groupByClause,orderByClause,isDynamicWhereClause;
EXIT when Process_Report%NOTFOUND;
tableName := getSourceTableName(tablePrefix,sourceTableType,processDate);
Process_Date := processDate;
processQuery := insertClause || selectClause ||' from ' || tableName ||' ' ||
nvl(whereClause,'') ||''||nvl(groupByClause,'') ||''||nvl(orderByClause,'') ||''||nvl(onUpdateClause,'');
dbms_output.put_line(processQuery);
IF isDynamicWhereClause = 'Y'
THEN
dbms_output.put_line(processQuery);
EXECUTE IMMEDIATE processQuery USING Process_Date;
ELSE
EXECUTE IMMEDIATE processQuery;
END IF;
END LOOP;
CLOSE Process_Report;
END;
While executing the proc it is giving me the below error.
Error report -
ORA-00936: missing expression
ORA-06512: at "Mytest.dynamicWhereClause", line 44
ORA-06512: at line 1
00936. 00000 - "missing expression"
Please assist me further
Thanks

Your questions is not 100% clear . you saying after DATEE is being empty, are you assigning a variable after date ? the below is example of how using execute immediate with a variable. Note how is the bind variable :i is showing in the print.
set serveroutput on size 1000
/
declare t number(4) :=10;
txt varchar2(100);
begin
txt :='INSERT INTO TAB (ID) values (:i)';
dbms_output.put_line(t || ' ' || txt);
execute immediate txt using T;
end;
/
PL/SQL procedure successfully completed
10 INSERT INTO TAB (ID) values (:i)

Related

Oracle Cursor within a Package not working - ORA 06512

I am trying to build a package that will take in a table of table names and either drop from or delete those tables. I am using dynamic sql, and dropping or deleting the tables works, but I need both the procedures to loop through all of the table names passed back to it.
I've tried mulitple ways - including trying to create a FOR Loop and a cursor. Here is a similar function I wrote in PostgreSQL that works but I'm having trouble translating it to Oracle.
Here is my function in PostgreSQL that works:
CREATE OR REPLACE FUNCTION drop_tables_for_stnd_mod_build(tablenames text)
RETURNS void
LANGUAGE plpgsql
AS $function$
DECLARE
tab_name RECORD;
BEGIN
FOR tab_name IN EXECUTE 'SELECT table_name FROM ' || tablenames
LOOP
EXECUTE 'DROP TABLE ' || tab_name.table_name || ' CASCADE';
END LOOP;
END;
$function$
;
And the procedure I'm writing as part of a package in Oracle
CREATE OR REPLACE PACKAGE BODY stnd_build_table_cleanup
AS
PROCEDURE drop_tables(table_in CLOB)
IS
TYPE cur_type is REF CURSOR;
c cur_type;
query_string VARCHAR(300);
loop_string VARCHAR(300);
table_name VARCHAR(100);
BEGIN
loop_string := 'SELECT tablenames FROM :table';
OPEN c FOR loop_string USING table_in;
LOOP
FETCH c INTO table_name;
query_string := 'DROP TABLE ' || table_name || ' CASCADE CONSTRAINTS';
-- dbms_output.PUT_LINE (query_string);
EXECUTE IMMEDIATE query_string;
EXIT WHEN c%NOTFOUND;
END LOOP ;
CLOSE c;
END drop_tables;
Here is the error I get when I try to call my function: Error report -
ORA-00903: invalid table name
ORA-06512: at "AMS_NYS.STND_BUILD_TABLE_CLEANUP", line 13
ORA-06512: at line 2
00903. 00000 - "invalid table name"
*Cause:
*Action:
Thanks!
Here's one possibility. Note that I coded this as a standalone procedure for simplicity.
CREATE OR REPLACE TYPE table_type IS TABLE OF VARCHAR2(128);
CREATE OR REPLACE PROCEDURE drop_tables(tables_to_drop_in table_type)
IS
BEGIN
FOR i IN tables_to_drop_in.FIRST .. tables_to_drop_in.LAST LOOP
--DBMS_OUTPUT.PUT_LINE(tables_to_drop_in(i));
EXECUTE IMMEDIATE 'DROP TABLE ' || tables_to_drop_in(i) || ' CASCADE CONSTRAINTS';
END LOOP;
END drop_tables;
DECLARE
tables_to_drop table_type;
BEGIN
tables_to_drop := table_type('TBL1','TBL2', 'TBL3');
drop_tables(tables_to_drop);
END;

PL\SQL - Get counts of all tables in a schema - errors

I want to get a result: table name, count amount for each table from AS_TABLE_LIST.
create procedure AtRowCount
as
declare
TableCount NUMBER(1);
TableName VARCHAR2(100);
BEGIN
SelectQuery1:= 'SELECT count(*) FROM ' || TableName || ' INTO ' || TableCount;
FOR TableName IN (select table_name from AS_TABLE_LIST)
LOOP
EXECUTE IMMEDIATE SelectQuery1;
END LOOP;
select TableName, TableCount into AT_ROW_COUNT from dual;
END AtRowCount;
I get two errors:
[Error] PLS-00306 (7: 19): PLS-00306: wrong number or types of
arguments in call to '||'
[Error] ORA-00904 (9: 8): PL/SQL: ORA-00904: "TABLENAME": invalid
identifier
I've been trying many times to fix this but still got same errors.
any advice?
I'm not exactly sure what you're trying todo, but it might be the following:
CREATE PROCEDURE AtRowCount AS
DECLARE
l_count NUMBER;
BEGIN
FOR c IN (SELECT table_name from AS_TABLE_LIST) LOOP
EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM '||c.table_name INTO l_count;
INSERT INTO AT_ROW_COUNT(TableName, TableCount )
VALUES (c.table_name, l_count);
END LOOP;
END AtRowCount;
If you want you're procedure to return the list instead of inserting the result in a new table, you have to use a pipelined function instead (see https://oracle-base.com/articles/misc/pipelined-table-functions for an example on how to use it).
You can get all rows count against table name in oracle by:
select owner, table_name, nvl(num_rows,-1)
from all_tables
order by nvl(num_rows,-1) desc
https://livesql.oracle.com/apex/livesql/file/content_EPJLBHYMPOPAGL9PQAV7XH14Q.html
Hope this will work for you
CREATE PROCEDURE atrowcount
IS
selectquery1 VARCHAR2(2000);
tablecount NUMBER;
BEGIN
selectquery1:= 'SELECT count(1) FROM :TableName';
FOR i IN (select table_name from AS_TABLE_LIST)
LOOP
EXECUTE IMMEDIATE selectquery1 INTO tablecount USING i.table_name;
INSERT INTO table_list VALUES(i.table_name,TableCount);
END LOOP;
COMMIT;
END AtRowCount;

Oracle EXECUTE immediate UPDATE [duplicate]

This question already has answers here:
Is it possible to pass table name as a parameter in Oracle?
(3 answers)
Closed 4 years ago.
I am just started to study Oracle. When I Execute Following Statement
DECLARE
sql_stmt VARCHAR2(200);
table_obj user_tables.table_name%type;
begin
for l_i in (select table_name from results) loop
table_obj := dbms_assert.sql_object_name(l_i.table_name);
sql_stmt := 'update results set cnt_record = ( select count(*) from :1) where table_name = UPPER(:2)';
EXECUTE IMMEDIATE sql_stmt
USING table_obj, l_i.table_name;
end loop;
end;
I get an error:
Error report -
ORA-00903: invalid table name
ORA-06512: at line 11
00903. 00000 - "invalid table name"
*Cause:
*Action:
You are only allow to pass constant names into an expression. You are not allowed to pass table names, column names, operators, function names and so on.
So, you have to "munge" the query string before you execute it:
table_obj := dbms_assert.sql_object_name(l_i.table_name);
sql_stmt := 'update results set cnt_record = ( select count(*) from <tablename>) where table_name = UPPER(:1)';
sql_stmt := replace(sql_stmt, '<tablename>', table_obj);
EXECUTE IMMEDIATE sql_stmt
USING l_i.table_name;
end loop;
end;
You could replace both occurrences using replace(), but the argument in upper() is fine for a parameter.

The dynamic sql in the stored procedure

I would like to pass in a dynamic column name to calculate its standard deviation,in oracle, the following is the code:
CREATE OR REPLACE
PROCEDURE ReportCalculate
(
param_columnName IN VARCHAR2 DEFAULT 'COMPUTED_CP_MLIFTOFF_KNOT9OR10'
)
AS
sqlstr VARCHAR2(500);
result NUMBER;
BEGIN
sqlstr:='select stddev(:col) from LIDISUDUXIAO where 1=1 and NO_10_LIMITSIGN_DEPART_ID<>0';
execute immediate sqlstr into result using param_columnName;
DBMS_OUTPUT.PUT_LINE(result);
END;
I call it with the default parameters,the error message is:
Procedure execution failed
ORA-01722: invalid number
ORA-06512: at "AGS.REPORTCALCULATE", line 10
ORA-06512: at line 1
How can i solve it?
A column name cannot be used as parameter of a query. You need to edit the sqlstr variable to include the provided param_columnName in the query itself before executing it:
CREATE OR REPLACE
PROCEDURE ReportCalculate
(
param_columnName IN VARCHAR2 DEFAULT 'COMPUTED_CP_MLIFTOFF_KNOT9OR10'
)
AS
sqlstr VARCHAR2(500);
result NUMBER;
BEGIN
sqlstr:='select stddev(' || param_columnName || ') from LIDISUDUXIAO where 1=1 and NO_10_LIMITSIGN_DEPART_ID<>0';
execute immediate sqlstr into result;
DBMS_OUTPUT.PUT_LINE(result);
END;

What is wrong with my PLSQL dynamic code?

I'm learning PLSQL since 3 or 4 months, and now I'm practicing Dynamic SQL and I've write a simple procedure to update last name of an employee with Dynamic SQL. I don´t know what is the problem because when I call the procedure and insert the parameters I receive an error.
CREATE OR REPLACE PROCEDURE upd_emp_dyn(
p_tname VARCHAR2,
p_lname employees.last_name%TYPE,
p_empid employees.employee_id%TYPE)
IS
v_dyn_stmt VARCHAR2(200) := 'UPDATE ' || p_tname ||
' SET last_name = ' ||
p_lname || ' WHERE employee_id = ' ||
p_empid;
v_confirm_stmt VARCHAR2(200) := 'SELECT * FROM ' || p_tname ||
' WHERE employee_id = ' ||
p_empid;
BEGIN
EXECUTE IMMEDIATE v_dyn_stmt;
DBMS_OUTPUT.PUT_LINE(v_confirm_stmt);
END upd_emp_dyn;
/
SHOW ERRORS;
SET SERVEROUTPUT ON
BEGIN
upd_emp_dyn('employees', 'Rooney', 120);
END;
/
Error que empieza en la línea: 2 del comando :
BEGIN
upd_emp_dyn('employees', 'Rooney', 120);
END;
Informe de error -
ORA-00904: "ROONEY": invalid identifier
ORA-06512: at "HR.UPD_EMP_DYN", line 14
ORA-06512: at line 2
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
The best practice (for both performance and security) is to use parameters:
CREATE OR REPLACE PROCEDURE upd_emp_dyn(
p_tname VARCHAR2,
p_lname employees.last_name%TYPE,
p_empid employees.employee_id%TYPE)
IS
v_dyn_stmt VARCHAR2(200) := 'UPDATE ' || p_tname ||
' SET last_name = :1 WHERE employee_id = :2';
v_confirm_stmt VARCHAR2(200) := 'SELECT * FROM ' || p_tname ||
' WHERE employee_id = :1';
BEGIN
EXECUTE IMMEDIATE v_dyn_stmt using p_lname, p_empid;
DBMS_OUTPUT.PUT_LINE(v_confirm_stmt);
END upd_emp_dyn;
/
SHOW ERRORS;
SET SERVEROUTPUT ON
BEGIN
upd_emp_dyn('employees', 'Rooney', 120);
END;
/
For select statements use following:
declare
result my_table%rowtype;
id number := 123;
begin
execute immediate 'select * from my_table where id = :1' into result using id;
end;
/
Also, it helps you to avoid typo errors (like which caused this question). And of course, you should avoid the use of dynamic SQL if it is possible to use static.
Instead of declaring table name as separate variable as parameter in your procedure..you can write a cursor for employees table & call that cursor in your dynamic query to print the output. So your dynamic sql in your proc will be more simple.