Create nested procedure in Oracle 10g - oracle

I want to create a nested procedure where in the 1st procedure, I want to create a table dynamically with 2 columns and in the 2nd procedure, I want to insert values into that table.
Below is the code I am trying to use; what am I doing wrong?
CREATE or replace PROCEDURE mytable (tname varchar2)
is
stmt varchar2(1000);
begin
stmt := 'CREATE TABLE '||tname || '(sname varchar2(20) ,sage number (4))';
execute immediate stmt;
end;
create PROCEDURE mytable1 (emp_name varchar2,emp_age number,tname varchar2)
is
stmt1 varchar2(1000);
begin
stmt1 := 'insert into '||tname||' values ('Gaurav' ,27)';
execute immediate stmt1;
end;

There's no need to create a nested procedure here. You can do everything in a single procedure.
Note my use of bind variables in the execute immediate statement
create or replace procedure mytable (
Ptable_name in varchar2
, Pemp_name in varchar2
, Pemp_age in number
) is
begin
execute immediate 'create table ' || Ptable_name
|| ' (sname varchar2(20), sage number (4))';
execute immediate 'insert into ' || Ptable_name
|| ' values (:emp_name, :emp_age)'
using Pemp_name, Pemp_age;
end;
More generally, there's no need to use execute immediate at all; creating tables on the fly is indicative of a poorly designed database. If at all possible do not do this; create the table in advance and have a simple procedure to insert data, should you need it:
create or replace procedure mytable (
, Pemp_name in varchar2
, Pemp_age in number
) is
begin
insert into my_table
values (Pemp_name, Pemp_age);
end;
I would highly recommend reading Oracle's chapter on Guarding Against SQL Injection.
If you really feel like you have to do this as a nested procedure it would look like this; don't forget to call the nested procedure in the main one as the nested procedure isn't visible outside the scope of the first.
create or replace procedure mytable (
Ptable_name in varchar2
, Pemp_name in varchar2
, Pemp_age in number
) is
procedure myvalues (
Pemp_name in varchar2
, Pemp_age in number
) is
begin
execute immediate 'insert into ' || Ptable_name
|| ' values (:emp_name, :emp_age)'
using Pemp_name, Pemp_age;
end;
begin
execute immediate 'create table ' || Ptable_name
|| ' (sname varchar2(20), sage number (4))';
myvalues ( Pemp_name, Pemp_age);
end;
Please see Oracle's documentation on PL/SQL subprograms

Related

How can I make table name from two string column?

I need to make a PL/SQL script.
The inputs are a schema name and a table name. How can I make it to a table name?
So e.g. I'd like to do this:
create or replace procedure proc(schema in varchar2, table in varchar2) is
begin
select * from 'schema.table';
end;
begin
proc('db', 'items');
end;
So I'd like to get everything from db.items.
I've tried concat, ( 'schema' || '.' || 'table'), put it in a variable, but non of these has worked.
What you need is dynamic sql. Example that will return and print the count of rows (you can change it accordingly to your needs):
SQL> set serveroutput on -- to be able to see the printed results.
SQL> create or replace procedure proc(p_schema in varchar2, p_table in varchar2) is
v_sql varchar2(100);
v_result number;
begin
v_sql := 'select count(*) from :1' || '.' || ':2';
EXECUTE IMMEDIATE v_sql into v_result USING p_schema, p_table;
DBMS_OUTPUT.PUT_LINE ('Total rows in table: '|| v_result );
end;

how to store and call a sql query from a table column?

Insert statement below holds details of another Table that has 3 columns (id,ins_dt,text_stuff)
INSERT INTO swpurge_config
(schema
,table_name
,table_alias
,driving_column
,deletion_predicate
,retention_period_type
,retention_period_value)
VALUES
('CUSTOMERS_OWNER'
,'LAST_NAMES'
,'LN'
,'ins_dt'
,'WHERE ln.ins_dt < SYSDATE - p_retention_period_value
AND ora_hash(ln.rowid, 8) = 1'
,'month'
,'6');
Aim:
I am essentially trying to add a delete predicate in a varchar2 column. The idea is to call this column in a Procedure which will delete records up to 1000 rows:
PROCEDURE delete_rows
(
p_schema IN VARCHAR2
,p_table_name IN VARCHAR2
,p_table_alias in varchar2
,p_retention_period_value IN VARCHAR2
,p_delete_predicate IN VARCHAR2
) IS
v_sql varchar2 (32000);
v_row_limit pls_integer (1000);
BEGIN
v_sql := 'delete from ' || p_schema ||'.'|| table_name ||p_table_alias
'older than '|| p_retention_period_value || p_delete_predicate;
dbms_output.put_line(v_sql);
END delete_rows;
Not sure about 2 things:
1. How to store the sql where clause in a table column?
2. How to execute the where clause as a statement in the procedure?
Thanks
you are talking about Dynamic SQL.
You can just store it inside VARCHAR2 in string format. then retrieve it
select deletion_predicate into v_sql from swpurge_config where ...
then
v_sql := "SELECT ...... FRom .... " || v_sql;
finally execute it
EXECUTE IMMEDIATE v_sql;
if your sql statement also includes parameters then
EXECUTE IMMEDIATE query_str
using param1;

Passing table name inside proc to store its row count into a variable

I want to write a simple pl/sql procedure which will take a table name as input and it will store the table row count into a variable . I have written the bellow code :
CREATE OR REPLACE procedure ATT_REP.proc_compare2(table_name IN varchar2)
is
cnt NUMBER(30);
begin
execute immediate 'select count(*) from '||table_name||' into '||cnt ;
dbms_output.put_line(cnt);
end;
/
while executing i am getting 'PLS-00357: Table,View Or Sequence reference 'CES_ODS.ENTITY' not allowed in this context' error.
Please suggest what am i doing wrong . How can i make it working .
Try the following:
CREATE OR REPLACE PROCEDURE ATT_REP.proc_compare2 (table_name IN VARCHAR2)
IS
cnt NUMBER (30);
sql_stmt VARCHAR2 (200);
BEGIN
sql_stmt := 'select count(*) from ' || table_name;
EXECUTE IMMEDIATE sql_stmt INTO cnt;
DBMS_OUTPUT.put_line (cnt);
END;
/

Create a table with oracle pl/sql

I get this error ORA-00933: SQL command not properly ended, but I cannot see what the problem is.
Creates the package:
CREATE OR REPLACE PACKAGE "TOOL_PKG" IS
PROCEDURE CREATE_ZTEMP_CLAIMS_TABLES;
END TOOL_PKG;
/
Create a procedure for the package. I get the error trying to run the procedure.
What I want to do is create a new table with an existing table. I need it dynamic because I'll be adding a lot more tables to the list.
CREATE OR REPLACE PACKAGE BODY CUBS_OWNER."TOOL_PKG" IS
PROCEDURE CREATE_NEW_TABLE IS
type array_t is table of varchar2(50) index by pls_integer;
my_table_t array_t;
elem varchar2(50);
c int;
BEGIN
my_table_t (1) := 'MY_TABLE';
elem := my_table_t.first;
while elem is not null loop
select count(*) into c from user_tables where table_name = upper('ZTEST_'||my_table_t(elem));
if c=0 then
Begin
execute immediate 'CREATE TABLE upper(NEWX_'||my_table_t(elem)||') AS SELECT * FROM upper('||my_table_t(elem)||') where rownum=0';
COMMIT;
DBMS_OUTPUT.put_line ('ZTEST_'||my_table_t(elem)||' created.');
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
'tool_pkg.create_new_table...failed creating table '
|| CHR (10)
|| SQLERRM);
END;
end if;
elem := my_table_t.next(elem);
end loop;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
'tool_pkg.create_new_table...failed creating table '
|| CHR (10)
|| SQLERRM);
END;
END tool_pkg;
/
I had to make sure the methods upper were outside the quotes.
Instead of this
execute immediate 'CREATE TABLE upper(NEWX_'||my_table_t(elem)||') AS SELECT * FROM upper('||my_table_t(elem)||') where rownum=0';
It had to be in this form
execute immediate 'CREATE TABLE '||upper('NEWX_'||my_table_t(elem))||' AS SELECT * FROM '||upper(my_table_t(elem))||' where rownum=0';

In Oracle PL/SQL can we insert bulk data dynamically?

I have a requirement to insert bulk data through procedure but the table and columns will be dynamic.
Suppose for one account there is one table and they have their configured columns, similarly there can be 1000 of such accounts, so there will 1000 number tables and their columns.
How can we achieve this in a single procedure?
A very primitive example, just so you get the feeling:
CREATE OR REPLACE PROCEDURE yourProcedure (tableName VARCHAR2,
colName1 VARCHAR2, colName2 VARCHAR2, colName3 VARCHAR2) IS
v_column VARCHAR2(30);
sql_stmt VARCHAR2(200);
BEGIN
sql_stmt := 'SELECT ' || colName1 || ', ' || colName2 || ', ' colName3 || ' FROM ' || tableName
EXECUTE IMMEDIATE sql_stmt;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Node Data Found');
END yourProcedure;
You could pass an array of columns instead of 3 columns only, if you the columns you need to select are not known beforehand.
You can also bind variables to the select statement adding the "USING" clause. Refer to documentation examples: http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/dynamic.htm#CHDGJEGD

Resources