Execute Oracle SQL command after PL/SQL block - sql

I've an SQL file which has some PL/SQL scripts and some DML scripts, but I'm not able to run normal DML commands just after a PL/SQL block IN SQL Developer. For e.g.
BEGIN
-- Some Statements
END;
UPDATE TABLE TABLE_NAME SET FLD_NAME = SOMETHING;
Do I need to change anything here so that I can run these commands.
PS: I don't want to put everything in BEGIN ... END block.

try put / after anonymous block:
BEGIN
-- Some Statements
END;
/
UPDATE TABLE TABLE_NAME SET FLD_NAME = SOMETHING;

Related

Can we have commit statement in Oracle SQL functions

Is it possible/make sense to have COMMIT statement in SQL functions?
Technically, the answer ist yes. You can do the following:
create or replace function committest return number as
begin
update my_table set col = 'x';
commit;
return 1;
end;
/
declare
number n;
begin
n := committest();
end;
/
However, you can't do the following:
select committest() from dual;
this would be a commit during a query and thus result in a
ORA-14552: Cannot Perform a DDL Commit or Rollback Inside a Query or DML
Yes, you can do that if you make the function an autonomous transaction. That way it will not be part of the current transaction anymore.
create or replace function doIt
as
pragma autonomous_transaction;
begin
... code ...
commit;
end;
/
More documentation
No, it's not possible, see the documentation:
https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_5009.htm
Restrictions on User-Defined Functions
.... In addition, when a function is called from within a query or DML
statement, the function cannot: ....
Commit or roll back the current transaction, create a savepoint or roll back to a savepoint, or alter the session or the system. DDL
statements implicitly commit the current transaction, so a
user-defined function cannot execute any DDL statements.

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.

EXECUTE IMMEDIATE ' some commands '

Is it possible to execute some sql commands within one EXECUTE IMMEDIATE block?
What is wrong with this syntax:
declare
pragma autonomous_transaction;
begin
execute immediate
'begin
COMMENT ON TABLE t1 IS ''description1'';
COMMENT ON TABLE t2 IS ''description2'';
end;';
end;
For one SQL command it works fine:
declare
pragma autonomous_transaction;
begin
execute immediate ' COMMENT ON TABLE t1 IS ''description1'' ';
end;
The begin end within the string to execute immediate is going to be treated as a PL/SQL anonymous block. DDL, such as COMMENT is not allowed in PL/SQL. If it were you wouldn't need to use execute immediate. Oracle essentially works with either a block of PL/SQL statement or a single SQL statement at a time. Though there are APIs to batch SQL statements too.
So, to run COMMENT within a PL/SQL block or procedure, you will need to execute immediate statements.
Without more context I can not intelligently comment on whether that is the right approach, or if just having the two comment statements stand alone would be better.
Well, you could do this:
begin
execute immediate
'begin
execute immediate ''COMMENT ON TABLE t1 IS ''''description1'''' '';
execute immediate ''COMMENT ON TABLE t2 IS ''''description2'''' '';
end;';
end;
But there's not much point.

drop tablespace if do not exist

I have written pl/sql script (works, but doesn't look nice):
DECLARE
v_exists NUMBER;
BEGIN
SELECT count(*) INTO v_exists FROM dba_tablespaces WHERE tablespace_name = 'hr_test';
IF v_exists > 0 THEN
BEGIN
EXECUTE IMMEDIATE 'DROP TABLESPACE hr_test INCLUDING CONTENTS AND DATAFILES CASCADE CONSTRAINTS';
END;
END IF;
EXECUTE IMMEDIATE 'CREATE TABLESPACE hr_RJ DATAFILE ''E:\hr_test_01.dbf'' SIZE 16M';
END;
Is there any way to rewrite this script without EXECUTE IMMEDIATE?
No. You cannot issue DDL statements in static PL/SQL.
And yes, it is perfectly fine to use native dynamic SQL for DDL purposes:
You need dynamic SQL in the following
situations:
You want to execute a SQL data
definition statement (such as CREATE),
a data control statement (such as
GRANT), or a session control statement
(such as ALTER SESSION). In PL/SQL,
such statements cannot be executed
statically.
Oracle dynamic SQL

Condition in SQL script

I've got an SQL-script executed by SQL*Plus, that needs to run with Oracle 10g and Oracle 11g.
That script gives grants on a package that does not exist before 11g:
GRANT EXECUTE ON sys.dbms_result_cache TO my_user;
I would like to avoid the exception on 10g, since I want to react to other exceptions in the script.
One way is to use Conditional Compilation and dbms_db_version:
BEGIN
$IF dbms_db_version.ver_le_10 $THEN NULL; $ELSE
EXECUTE IMMEDIATE 'GRANT EXECUTE ON sys.dbms_result_cache TO my_user';
$END
END;
/
Is there any other way, preferable without using PL/SQL?
Your question and one of the comments indicate that you want to avoid PL/SQL blocks and EXECUTE IMMEDIATE. I also assume that by "react to other exceptions" you mean abort execution of the script when an exception is encountered.
If so, I think the best you can do in pure SQL/SQL*Plus is to ignore the exception exit for the grant statement:
... first part of script (with exit on sqlerror in effect)
WHENEVER SQLERROR CONTINUE
GRANT EXECUTE ON sys.dbms_result_cache TO my_user;
WHENEVER SQLERROR EXIT SQL.SQLCODE
... remaining part of script
you could check if the object exists beforehand:
BEGIN
FOR cc IN (SELECT NULL
FROM all_objects
WHERE owner = 'SYS'
AND object_name = 'DBMS_RESULT_CACHE'
AND ROWNUM = 1) LOOP
EXECUTE IMMEDIATE 'GRANT EXECUTE ON sys.dbms_result_cache TO my_user';
END LOOP;
END;
You can simulate branching by writing SQL that generates SQL and spools it to a sql script. Then run the sql script:
define temp_file='somefile.sql'
set heading off
set feedback off
spool &&temp_file
SELECT 'GRANT EXECUTE ON sys.dbms_result_cache TO my_user;'
FROM all_objects
WHERE owner = 'SYS'
AND object_name = 'DBMS_RESULT_CACHE';
spool off
#&&temp_file
host rm &&temp_file
Thanks to #Vincent for the data dictionary query.