Oracle Stored Procedure with Alter command - sql

I am trying to build an Oracle stored procedure which will accept a table name as a parameter. The procedure will then rebuild all indexes on the table.
My problem is I get an error while using the ALTER command from a stored procedure, as if PLSQL does not allow that command.

Use the execute immediate statement to execute DDL inside PL/SQL.
create procedure RebuildIndex(index_name varchar2) as
begin
execute immediate 'alter index ' || index_name || ' rebuild';
end;
I tested this code; it works.

Documentation.
Passing Schema Object Names As Parameters
Suppose you need a procedure that
accepts the name of any database
table, then drops that table from your
schema. You must build a string with a
statement that includes the object
names, then use EXECUTE IMMEDIATE to
execute the statement:
CREATE TABLE employees_temp AS SELECT last_name FROM employees;
CREATE PROCEDURE drop_table (table_name IN VARCHAR2) AS
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ' || table_name;
END;
/
Use concatenation to build the string,
rather than trying to pass the table
name as a bind variable through the
USING clause.
In addition, if you need to call a
procedure whose name is unknown until
runtime, you can pass a parameter
identifying the procedure. For
example, the following procedure can
call another procedure (drop_table) by
specifying the procedure name when
executed.
CREATE PROCEDURE run_proc (proc_name IN VARCHAR2, table_name IN VARCHAR2) ASBEGIN
EXECUTE IMMEDIATE 'CALL "' || proc_name || '" ( :proc_name )' using table_name;
END;
/
If you want to drop a table with the
drop_table procedure, you can run the
procedure as follows. Note that the
procedure name is capitalized.
CREATE TABLE employees_temp AS SELECT last_name FROM employees;
BEGIN
run_proc('DROP_TABLE', 'employees_temp');
END;
/

Here are a couple of possibilities. First, you would have to treat the SQL as dynamic SQL. Second, Oracle DDL statements cannot be run in a transaction (or, they terminate the current transaction and cannot themselves be rolled back). This may affect whether you can use them in stored procedures, or where you can use stored procedures that contain them.
If none of the above apply at all - there could easily be something else astray - I suggest posting some code.

Related

BigQuery save OPTIONS(strict_mode=FALSE) in procedure

I have procedure below which create procedure in different projects
CREATE OR REPLACE PROCEDURE `sp_get_data`(arg_ProjectID STRING, arg_DatasetID STRING)
OPTIONS(strict_mode=FALSE)
BEGIN
EXECUTE IMMEDIATE
"CREATE OR REPLACE PROCEDURE `"|| arg_ProjectID || "." || arg_DatasetID || ".sp_get_data_details`() \r\n"||
"BEGIN
-- lengthy code
"END"
;
END;
The code insde procedure is very very lengthy.
When I run this create procedure with OPTIONS(strict_mode=FALSE), it is working..., but it doesn't not save in procedure script..
how to make it persist in procedure script
without it throws error
Query error: Out of stack space due to deeply nested query expression
during query resolutio
But how can I add this dynamically when calling like
call sp_get_data(projectid,datasetid)
Any help,
Highly appreciated

How to convert every Table from a specific User to JSON Format using the "trick" provided by SQL Developer

I want to convert all tables from a specific user to JSON (or XML) Format. I've read about a "trick" mentioned by SQL Developer.
In other words, I already started to create a Procedure with two parameters:
p_format: The format (in my case it will be "json")
p_user: The username
As IDE I use Oracle SQL Developer and my database is an Oracle XE Database.
At first the procedure loops though all tables of the given user and in the loop, it should execute the following:
SELECT /*p_format*/ * FROM p_user || '.' || table
Unfortunately, I cannot use this SELECT Statement as mentioned above. I need to use the command EXECUTE IMMEDIATE <Statement>.
The next problem I faced was the following: I wanted to output the result of the EXECUTE IMMEDIATE command. Therefore I used the command EXECUTE IMMEDIATE <Statement> INTO <Variable>. After compiling the procedure and executing it, I stumpled across the following Error:
"inconsistent datatypes: expected %s got %s"
This is my code of the procedure:
CREATE OR REPLACE PROCEDURE EXPORT_TABLE_TO_FORMAT_FROM(p_format VARCHAR2, p_user VARCHAR2) IS
/***************************************************************************
Author:
Class:
School:
Date:
Function - EXPORT_TABLE_TO_JSON_FROM(p_user):
Displays the data of every table from a given User as JSON
Parameter: p_user ... User
***************************************************************************/
v_tableData VARCHAR2(32767);
v_sqlStatement VARCHAR2(200);
BEGIN
FOR tablerec IN (SELECT *
FROM ALL_TABLES
WHERE OWNER = p_user)
LOOP
v_sqlStatement := 'SELECT /*' || p_format || '*/ * FROM ' || p_user || '.' || tablerec.TABLE_NAME;
EXECUTE IMMEDIATE v_sqlStatement INTO v_tableData;
DBMS_OUTPUT.PUT_LINE (v_sqlStatement);
END LOOP;
END;
You can see that I loop though all tables of a given user and created a sql statement with p_format and p_user and with tablerec.TABLE_NAME.
The desired result should look exactly like that:
{"results":[{"columns":[{"name":"COUNTRY_ID","type":"CHAR"},
{"name":"COUNTRY_NAME","type":"VARCHAR2"},{"name":"REGION_ID","type":"NUMBER"}],"items":
[
{"country_id":"AR","country_name":"Argentina","region_id":2},
{"country_id":"AU","country_name":"Australia","region_id":3},
{"country_id":"BE","country_name":"Belgium","region_id":1},
{"country_id":"BR","country_name":"Brazil","region_id":2},
{"country_id":"CA","country_name":"Canada","region_id":2},
{"country_id":"CH","country_name":"Switzerland","region_id":1},
{"country_id":"CN","country_name":"China","region_id":3},
{"country_id":"DE","country_name":"Germany","region_id":1},
{"country_id":"DK","country_name":"Denmark","region_id":1},
{"country_id":"EG","country_name":"Egypt","region_id":4},
{"country_id":"FR","country_name":"France","region_id":1},
{"country_id":"IL","country_name":"Israel","region_id":4},
{"country_id":"IN","country_name":"India","region_id":3},
{"country_id":"IT","country_name":"Italy","region_id":1},
{"country_id":"JP","country_name":"Japan","region_id":3},
{"country_id":"KW","country_name":"Kuwait","region_id":4},
{"country_id":"ML","country_name":"Malaysia","region_id":3},
{"country_id":"MX","country_name":"Mexico","region_id":2},
{"country_id":"NG","country_name":"Nigeria","region_id":4},
{"country_id":"NL","country_name":"Netherlands","region_id":1},
{"country_id":"SG","country_name":"Singapore","region_id":3},
{"country_id":"UK","country_name":"United Kingdom","region_id":1},
{"country_id":"US","country_name":"United States of America","region_id":2},
{"country_id":"ZM","country_name":"Zambia","region_id":4},
{"country_id":"ZW","country_name":"Zimbabwe","region_id":4}]}]}
The JSON hint is specific to SQL Developer and SQLcl, not the database directly. So you need to run the entire thing within these tools.
Easiest way to do that is to have your script write a script that you can then run, eg
spool /tmp/get_all_json.sql
select 'select /*json*/ * from '||table_name||';'
from user_tables;
spool off
#/tmp/get_all_json.sql

Netteza SQL ALTER TABLE in stored procedure alternative?

I want to alter a table within a For loop in Netteza SQL. I know that Netteza does not allow alter table in a stored procedure. As quoted:
"These SQL commands are also prohibited within the body of a Netezza stored procedure."
Are there any alternatives for doing so? I am a beginner in Netteza. I also don't know if my loop format is correct?
CREATE OR REPLACE PROCEDURE "SP_Automate_Table"()
RETURNS INTEGER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
vSQL1 varchar(30000) ;
BEGIN
FOR i in 2011..2014
LOOP
For j in 1..12
Loop
call "SP_Count"(i, j);
vSQL1:='alter table X add columnX INT';
....
...
..
EXECUTE immediate vSQL1;
END LOOP;
END LOOP;
END;
END_PROC;
Starting with v7.1 you can declare an AUTOCOMMIT ON block in a stored procedure, and in this block you can call statements that would otherwise be prohibited within a stored procedure.
CREATE OR REPLACE PROCEDURE ADMIN.SP_ALTER_LOOP(INTEGER, INTEGER)
RETURNS INTEGER
LANGUAGE NZPLSQL AS
BEGIN_PROC
DECLARE
pStartVal ALIAS FOR $1;
pCount ALIAS FOR $2;
vSQL varchar(30000);
BEGIN
BEGIN AUTOCOMMIT ON
for i in 1 .. pCount LOOP
vSQL := 'ALTER TABLE CLAIM_' || pStartVal + i-1 || ' ADD COLUMN (COL2 BIGINT);';
EXECUTE IMMEDIATE vSQL;
END LOOP;
END;
END;
END_PROC;
Prior to v7.1, I don't know of a way you can alter a table structure from with a stored procedure.
Note that in the general case of ALTER TABLE (whether scripted like this or manual), be sure to perform a groom of each altered table after the ALTER operation.
GROOM TABLE tablename VERSIONS;
Your loop statement is syntactically correct, but there is no way to issue alter statements from within nzplsql.
I would suggest doing a bash script as an alternative, repeatedly calling nzsql.
for i in $(seq 2011 2014); do
for j in $(seq 1 12); do
nzsql -c "call \"SP_Count\"($i, $j);"
nzsql -c "alter table X add columnX INT;"
done
done
I can't really imagine a use case where you'd want to dynamically add columns by calling a stored procedure from within a database that couldn't also be covered by doing it outside the database.

Calling an Oracle procedure within a package from a different schema?

I've created the following package with 3 procedures:
CREATE OR REPLACE PACKAGE PQ_PaqueteIntegrantes
AS
PROCEDURE INTEG_INSERCIONES(paIdIntegrante IN CreadorTablas.INTEGRANTES.ID_INTEGRANTE%TYPE
,paNombre IN CreadorTablas.INTEGRANTES.NOMBRE%TYPE
,paApellidoPaterno IN CreadorTablas.INTEGRANTES.APELLIDO_PATERNO%TYPE);
PROCEDURE INTEG_MODIFICACIONES(paIdIntegrante IN OUT CreadorTablas.INTEGRANTES.ID_INTEGRANTE%TYPE
,paNombre IN OUT CreadorTablas.INTEGRANTES.NOMBRE%TYPE
,paApellidoPaterno IN OUT CreadorTablas.INTEGRANTES.APELLIDO_PATERNO%TYPE);
PROCEDURE INTEG_ELIMINCACIONES(
paIdIntegrante IN OE.EJEMPLO_TRANSAC_CLASE.CUSTOMER_ID%TYPE
,paMjeDescError OUT VARCHAR2
,paCodeError OUT NUMBER);
END PQ_PaqueteIntegrantes;
I created those procedures with a user called Admin_proyectos. The first procedures makes "Inserts", the second one "Updates", and the last one "Deletes", all of them working on a table called Integrantes, that table comes from another user called CreadorTablas.
My intention is to create another user called Admin, who will have the responsibility to do those things, using the procedures from this package, of course. I've tried doing an PL/SQL block, but it didn't work, neither with an EXEC.
GRANT EXECUTE ON ADMIN_PROYECTOS.PQ_PaqueteIntegrantes TO Admin
Then, you can call the procedures in this package with Admin user as
BEGIN
ADMIN_PROYECTOS.PQ_PaqueteIntegrantes.INTEG_INSERCIONES(paIdIntegrante, paNombre, paNombre);
END;
You can use execute immediate statement:
l_sql_stmt := 'alter table ' || p_table_name || ' drop partition ' || i.PARTITION_NAME || ';';
dbms_output.put_line( l_sql_stmt );
execute immediate l_sql_stmt;

In a PL/SQL procedure, how do I pass a table name as a parameter?

CREATE PROCEDURE A(tab IN <table - what should I write here?>) AS
BEGIN
INSERT INTO tab VALUES(123);
END A;
How can I specify that the parameter tab is a table name?
You can't. Instead you need to pass it in as a VARCHAR2 string and then use Dynamic SQL:
CREATE PROCEDURE A(tab IN VARCHAR2) AS
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO ' || tab || 'VALUES(123)';
END A;
Read up about Dynamic SQL and be aware of the issues it can bring if used unwisely, such as poorer performance, scalability and security.