dynamic sql error ORA-00911 - sql

i have create the below simple code it will get table name dynamically and create a table as per the columns given in the input table
CREATE OR REPLACE
PROCEDURE dyn_sql_sp(
p_user VARCHAR2,
p_table_name VARCHAR2,
P_NW_tbl_name VARCHAR2)
AS
d_cols VARCHAR2(2000);
CURSOR col_c
IS
SELECT column_name
||' '
||data_type
||'('
||data_length
||')' colm
FROM All_Tab_Columns
WHERE owner =UPPER(p_user)
AND table_name=UPPER(p_table_name);
BEGIN
FOR i IN col_c
LOOP
d_cols:=d_cols||i.colm||',';
END LOOP;
D_Cols:=RTRIM(REPLACE(D_Cols,'DATE(7)','DATE'),',');
dbms_output.put_line( 'CREATE TABLE '||P_Nw_Tbl_Name||' ('||d_cols||');');
EXECUTE Immediate ' CREATE TABLE '||P_Nw_Tbl_Name||' ( '||d_cols||'); ';
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(sqlerrm||SQLCODE);
END;
but im getting error as
SQL> exec dyn_sql_sp('hr','departments','tamil');
CREATE TABLE tamil (DEPARTMENT_ID NUMBER(22),DEPARTMENT_NAME
VARCHAR2(30),MANAGER_ID NUMBER(22),LOCATION_ID NUMBER(22)
);
ORA-00911: invalid character
PL/SQL procedure successfully completed.
hope program is completely correct i can run the output separately and works fine but getting error while i dynamically create the same
SQL> CREATE TABLE tamil (DEPARTMENT_ID NUMBER(22),DEPARTMENT_NAME
2 VARCHAR2(30),MANAGER_ID NUMBER(22),LOCATION_ID NUMBER(22));
Table created.

The problem may be in the final ';' in the dynamic statement:
SQL> begin
2 execute immediate 'create table tab_one(a number);';
3 end;
4 /
begin
*
ERROR at line 1:
ORA-00911: invalid character
ORA-06512: at line 2
SQL> begin
2 execute immediate 'create table tab_one(a number)';
3 end;
4 /
PL/SQL procedure successfully completed.

Related

Creating database table in PL/SQL procedure

I am trying to create table with procedure CREATE_TABLE and then insert the information into the created table with procedure PRINT_INFO but I am getting an exception:
Errors: PROCEDURE PRINT_INFO Line/Col: 4/3 PL/SQL: SQL Statement
ignored Line/Col: 4/15 PL/SQL: ORA-00942: table or view does not exist
Errors: PROCEDURE CREATE_TABLE Line/Col: 5/3 PLS-00103: Encountered
the symbol "CREATE" when expecting one of the following:
( begin case declare exit for goto if loop mod null pragma raise
return select update while with << continue close current
delete fetch lock insert open rollback savepoint set sql execute
commit forall merge pipe purge json_exists json_value json_query
json_object json_array
And here is my code example:
CREATE OR REPLACE PROCEDURE PRINT_INFO
IS
BEGIN
INSERT INTO TABLE_T (TABLE_ID, MESSAGE) VALUES (1, 'Hello World!');
END PRINT_INFO;
/
CREATE OR REPLACE PROCEDURE CREATE_TABLE
IS
BEGIN
CREATE TABLE TABLE_T(
TABLE_ID NUMBER NOT NULL,
MESSAGE VARCHAR2(25),
PRIMARY KEY(TABLE_ID)
);
PRINT_INFO;
END CREATE_TABLE;
/
EXEC CREATE_TABLE;
Where could be the problem? How can I get rid of an exception?
Both procedures have to use dynamic SQL:
print_info because it inserts into a table which - at compilation time - doesn't exist yet
create_table because it runs DDL and - in order to do that - you need to use dynamic SQL
Therefore:
SQL> CREATE OR REPLACE PROCEDURE PRINT_INFO
2 IS
3 BEGIN
4 execute immediate q'[INSERT INTO TABLE_T (TABLE_ID, MESSAGE) VALUES (1, 'Hello World!')]';
5 END PRINT_INFO;
6 /
Procedure created.
SQL> CREATE OR REPLACE PROCEDURE CREATE_TABLE
2 IS
3 BEGIN
4 execute immediate 'CREATE TABLE TABLE_T(' ||
5 'TABLE_ID NUMBER NOT NULL, ' ||
6 ' MESSAGE VARCHAR2(25), ' ||
7 ' PRIMARY KEY(TABLE_ID) ' ||
8 ')';
9
10 PRINT_INFO;
11 END CREATE_TABLE;
12 /
Procedure created.
SQL> EXEC CREATE_TABLE;
PL/SQL procedure successfully completed.
SQL> SELECT * FROM table_t;
TABLE_ID MESSAGE
---------- -------------------------
1 Hello World!
SQL>
You have to declare a string and assign your ddl to that variable then use
execute immediate your_variable ;

How to write a PL/SQL procedure with an Instead Of Trigger as Dynamic SQL?

I wrote a PL/SQL function and am using dynamic SQL to execute a Create trigger statement as follows :-
CREATE OR REPLACE FUNCTION register_driver1(driver_name IN VARCHAR, pass_word IN VARCHAR) RETURN NUMBER AS
sql_stmt VARCHAR2(500);
driver_id NUMBER;
new_view_name VARCHAR(50); --<-----Line 4
BEGIN
--function statements
sql_stmt := 'CREATE OR REPLACE TRIGGER reg_vehicle
INSTEAD OF INSERT ON '||new_view_name||
' FOR EACH ROW
DECLARE
vehicle_id NUMBER;
BEGIN
vehicle_id := vehicle_ids.nextval
INSERT INTO Vehicles VALUES(:NEW.Model, :NEW.Seats, :NEW.reg_no, vehicle_id, '||driver_id||');
END;';
EXECUTE IMMEDIATE sql_stmt; --<-----Line 32
--Remaining function body
END;
/
Here, the variables new_view_name, driver_id are defined above this code snippet. Vehicle is a table(Model, Seats, Reg_no, vehicel_id, driver_id) and reg_vehicle(Model, Seats, Reg_no) is a view having Vehicles of a particular driver_id.
vehicle_ids is a sequence created outside the procedure.
The above shows compilation error at the EXECUTE IMMEDIATE line. What is the correct way to do this?
The error shown when function is called with some driver_name and pass_word:-
ORA-24344: success with compilation error ORA-06512: at "ADMIN.REGISTER_DRIVER1", line 32 ORA-06512: at line 4
Well, I wouldn't recommend creating objects dynamically.
If you - for some reason - insist on that, then another problem: you can't perform DDL here as you'd call a function as e.g.
select register_driver1(...) from dual;
and get
ORA-14552: cannot perform a DDL, commit or rollback inside a query or DML
So - switch to a procedure with an OUT parameter to return whatever that function is supposed to return.
As of error you got: you miss BEGIN. Something like this compiles:
SQL> CREATE OR REPLACE PROCEDURE register_driver1 (driver_name IN VARCHAR,
2 pass_word IN VARCHAR)
3 AS
4 sql_stmt VARCHAR2 (500);
5 driver_id NUMBER;
6 new_view_name VARCHAR (50);
7 BEGIN
8 sql_stmt :=
9 'CREATE OR REPLACE TRIGGER reg_vehicle
10 INSTEAD OF INSERT ON '
11 || new_view_name
12 || ' FOR EACH ROW
13 DECLARE
14 vehicle_id NUMBER;
15 BEGIN
16 vehicle_id := vehicle_ids.nextval
17 INSERT INTO Vehicles VALUES(:NEW.Model, :NEW.Seats, :NEW.reg_no, vehicle_id, '
18 || driver_id
19 || ');
20 END;';
21
22 -- EXECUTE IMMEDIATE sql_stmt;
23 DBMS_OUTPUT.put_line (sql_stmt);
24 END;
25 /
Procedure created.
SQL>
SQL> SET SERVEROUTPUT ON;
SQL> EXEC register_driver1('a', 'b');
CREATE OR REPLACE TRIGGER reg_vehicle
INSTEAD OF INSERT ON FOR
EACH ROW
DECLARE
vehicle_id NUMBER;
BEGIN
vehicle_id := vehicle_ids.nextval
INSERT
INTO Vehicles VALUES(:NEW.Model, :NEW.Seats, :NEW.reg_no, vehicle_id, );
END;
PL/SQL procedure successfully completed.
SQL>

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;

How to select from query string in oracle

Lets assume, I have a string that holds a query string.
How can I select the rows from that query string in oracle ?
I tried execute immediate but it returns nothing.
declare
hello varchar(30000);
begin
hello:='select * from test_table';
execute immediate hello;
end;
You would use a dynamic cursor.
Here's an example with SQL*Plus:
SQL> var dyn_cur refcursor
SQL> DECLARE
2 l_sql_query VARCHAR2(1000);
3 BEGIN
4 -- complex function that returns a query:
5 l_sql_query := 'SELECT 1, dummy FROM dual';
6 OPEN :dyn_cur FOR l_sql_query;
7 END;
8 /
PL/SQL procedure successfully completed.
SQL> print dyn_cur
1 DUM
---------- ---
1 X
You can use dynamic cursors in PL/SQL procedures and packages:
SQL> CREATE OR REPLACE PROCEDURE prc_dyn_cur(p_dyn_cursor OUT SYS_REFCURSOR) IS
2 BEGIN
3 OPEN p_dyn_cursor FOR 'SELECT 1, dummy FROM dual';
4 END;
5 /
Procedure created.
SQL> exec prc_dyn_cur(:dyn_cur);
PL/SQL procedure successfully completed.
SQL> print dyn_cur
1 DUM
---------- ---
1 X
declare
hello varchar(30000);
type tb is table of test_table$rowtype;
mytb tb;
begin
hello:='select * from test_table';
execute immediate hello bulk collect into mytb;
-- now you got all og youe data in the "array" mytb
end;
notice that this solution takes into account that you know what table you are selecting from.
plus, i think you should describe what exactly it is you are trying to achieve.
CREATE OR REPLACE PROCEDURE query_executer (string_query IN VARCHAR)
IS
c1 SYS_REFCURSOR;
v_last_name employees.last_name%TYPE; -- Selecting last_name
BEGIN
OPEN c1 FOR string_query; -- Opening c1 for the select statement
LOOP
FETCH c1 INTO v_last_name;
DBMS_OUTPUT.put_line (v_last_name);
EXIT WHEN (C1%NOTFOUND);
END LOOP;
END;
SET SERVEROUTPUT ON
EXECUTE query_executer('select last_name from employees');
OUTPUT
Procedure created.
Abel
Ande
Atkinso
PL/SQL procedure successfully completed.

oracle - mixing SQL code with PLSQL when no bindings in WHERE statement

I am trying to write a very simple sql script:
select * from table_X;
and I would like to see the results in oracle sqlplus, if there are any. These results are important for further analysis.
Also to mention, it depends, how many tables were created originally, so chances are that table_X may not be in the database at all. However I want to avoid getting an error, when parsing, that table_X doesn't exist, while running that script above.
So I was trying to wrap that SQL into some PLSQL dynamic code, like this:
Define table_X="MY_TAB"
DECLARE
stmt_ VARCHAR2(2000);
exist_ number := 0;
CURSOR table_exist IS
SELECT 1
FROM user_tables
WHERE table_name = '&table_X';
BEGIN
OPEN table_exist;
FETCH table_exist INTO exist_;
CLOSE table_exist;
IF exist_ = 1 THEN
stmt_ := 'SELECT * FROM &table_X';
EXECUTE IMMEDIATE stmt_;
ELSE
dbms_output.put_line('This functionality is not installed.');
END IF;
END;
/
Why I cannot see any result (records), if there is data in MY_TAB? Do I really need to bind some columns and use ex. dbms_output to be able to see some information?
Is there any simple way to query a table without getting 'ORA-00942: table or view does not exist'
if that table doesn't exist (ideally using SQL only)?
Thanks in advance
like this if you want it in sqlplus:
SQL> var c refcursor;
SQL> create or replace function get_table(p_tab in varchar2)
2 return sys_refcursor
3 is
4 v_r sys_refcursor;
5 NO_TABLE exception;
6 pragma exception_init(NO_TABLE, -942);
7 begin
8 open v_r for 'select * from ' || dbms_assert.simple_sql_name(p_tab);
9 return v_r;
10 exception
11 when NO_TABLE
12 then
13 open v_r for select 'NO TABLE ' || p_tab as oops from dual;
14 return v_r;
15 end;
16 /
Function created.
SQL> exec :c := get_table('DUAL2');
PL/SQL procedure successfully completed.
SQL> print c
OOPS
-----------------------------------------
NO TABLE DUAL2
SQL>
SQL> exec :c := get_table('DUAL');
PL/SQL procedure successfully completed.
SQL> print c
D
-
X
Instead of execute immediate 'query' you could use execute immediate 'query' bulk collect into and then loop over it and use dbms_output to print it.
http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/executeimmediate_statement.htm