Oracle Trigger with INSERT INTO table - sql

I am trying to create an Oracle Trigger with After Update statement. It appears that I cannot create the trigger because I get prompted with Table does not exist error:
CREATE OR REPLACE TRIGGER USR1.CORE_FINISHED
AFTER UPDATE OF RUNTIME_STATUS
ON USR2.runtime_btc
FOR EACH ROW
WHEN ( new.RUNTIME_STATUS = 'FINISHED'
AND new.id = 'cr_daily')
BEGIN
INSERT INTO USR1.test_dq_log (BTC_NO, TBL_NAM, SCR_NAM)
SELECT BTC_NO, TBL_NAM, SCR_NAM
FROM USR2.EVENT_LG -- This is where the script is throwing errors
WHERE BTC_NO = :NEW.BTC_NO;
END;
What is weird is that the same expression when run outside of the trigger:
INSERT INTO USR1.test_dq_log (BTC_NO, TBL_NAM, SCR_NAM)
SELECT BTC_NO, TBL_NAM, SCR_NAM
FROM USR2.EVENT_LG
WHERE BTC_NO = 'any number here'
Seems to work smoothly and it inserts rows in the table!

It looks as if you were granted privileges to insert into that table via role. Were you?
If so, it works at SQL level or anonymous PL/SQL blocks, but won't work in named PL/SQL procedures (e.g. stored procedures, functions, triggers) - you'll have to acquire that grant directly (not via role).

Related

Oracle: Setting Session Parameters in Packages and Procedures

I'm a SQL Server DBA currently getting up to speed on Oracle. I'm trying to create something very similar to sp_WhoIsActive for SQL Server but for Oracle without reinventing the wheel. Essentially all I'm doing is selecting some values from v$session and inserting them into a table (poor man's ASH/AWR).
It would seem that in Oracle 12.1, there's a bug when querying dictionary views where it can take forever due to bad parsing logic (Bug 22225899 : SLOW PARSE FOR COMPLEX QUERY). The work-around is to set a session parameter:
alter session set "_optimizer_squ_bottomup"=false;
In T-SQL, I could very easily execute a stored procedure in-session and set this variable at runtime. However in Oracle, it wouldn't seem thats the case.
Sample Code:
CREATE OR REPLACE PROCEDURE SP_DB_ACTIVITY
(
v_temp NUMBER :=1
) IS
BEGIN
alter session set "_optimizer_squ_bottomup"=false;
INSERT INTO SY_DB_ACTIVITY
SELECT
<fields>
FROM
v$session;
commit;
When I run this, I get the error:
"PLS-00103: Encountered symbol 'ALTER' when expecting one of the following..."
Right now, the only way I know how to do this is via a utility like SQL Plus that initiates an interactive user session. Can anyone give me some direction as to how Oracle handles this situation? I'd like to bundle this up into a SP or a Package and then call it from Oracle Scheduler.
Hre is a simple example how to execute alter session inside of the procedure:
CREATE PROCEDURE SP_DB_ACTIVITY IS
BEGIN
EXECUTE IMMEDIATE 'alter session set "_optimizer_squ_bottomup"=false';
END;
/
Here is the way you can combine that with your select and insert statement:
CREATE OR REPLACE PROCEDURE SP_DB_ACTIVITY
(v_temp IN number) AS
v_Id NUMBER;
BEGIN
EXECUTE IMMEDIATE 'alter session set "_optimizer_squ_bottomup"=false';
SELECT 1
INTO v_Id
FROM dual;
INSERT INTO SY_DB_ACTIVITY (id) VALUES(v_Id);
END SP_DB_ACTIVITY;
/
Here is a small DEMO where you can see what will procedure do when you call it and how you can call it. Also, in this example you are calling procedure with and IN parameter. So you can use that parameter for something and in the example above is the procedure without any parameters...
You can also, of course, insert into table directly:
CREATE OR REPLACE PROCEDURE SP_DB_ACTIVITY
(v_temp IN number) AS
v_Id NUMBER;
BEGIN
EXECUTE IMMEDIATE 'alter session set "_optimizer_squ_bottomup"=false';
INSERT INTO SY_DB_ACTIVITY(id)
select 1
from dual;
END SP_DB_ACTIVITY;
/

insert statement inside stored procedure failing

I have written a oracle stored procedure and creating an error log table if that doesn't exist.
SELECT COUNT(*)
INTO v_count
FROM all_tables
WHERE TABLE_NAME = 'ERROR_LOG';
IF v_count =0 THEN
cr_table := 'CREATE TABLE ERROR_LOG ( ERROR_LOG_ID NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY, IDENTIFIER VARCHAR2(100), ERROR_MESSAGE VARCHAR2(1000),created_by varchar2(100 ), created_date TIMESTAMP DEFAULT systimestamp )';
execute immediate cr_table;
then issuing an insert statement below in the code as
INSERT
INTO error_log
(
identifier,
error_message,
created_by
)
VALUES
(
v_identifier,
'Success',
v_user
);
But the SP is throwing compilation error with
PL/SQL: ORA-00942: table or view does not exist
If I create the table manually, offline, and compile then it works.
any help?
if you use execute immediate to create a table, it exists in the PL/SQL context, not in SQL context, you have to execute the INSERT by using execute immedation too.
Or you have to make the insert inside an other BEGIN.. END block.
Before using the stored procedure, please create a view or table where you are going to insert the values using the SP. So it will avoid the compiler error in the run time.
This is too long for a comment.
The table doesn't exist when the code is compiled. Hence, you are getting a compile-time error. At compilation time, Oracle doesn't know that the table will exist when executed.
One solution is to use dynamic SQL for the insert as well.
A better solution is to set up the database with the appropriate tables before the code can ever be executed. Creating permanent tables dynamically in conditional code is usually a sign of a poorly designed application.

PostgreSQL FOUND for CREATE TABLE statements

I am creating a function that will create a new table and insert informations about that table into other tables.
To create that table I am using the
CREATE TABLE IF NOT EXISTS
statement. Sadly it does not update the FOUND special variable in PostgreSQL nor can i find any other variable that would be updated.
Is there any way in PL/PGSQL to know whether that statement created a table or not?
The target of it is to not to double the informations in the other tables.
You may use CREATE TABLE AS in combination with ON_ERROR_ROLLBACK:
BEGIN;
-- Do inital stuff
\set ON_ERROR_ROLLBACK on
CREATE TABLE my_table AS
SELECT id, name FROM (VALUES (1, 'Bob'), (2, 'Mary')) v(id, name);
\set ON_ERROR_ROLLBACK off
-- Do remaining stuff
END;
To put it bluntly, with \set ON_ERROR_ROLLBACK on postgres will create a savepoint before each statement and automatically rollback to this savepoint or releasing it depending on the success of that statement.
The code above will execute initial and remaining stuff even if the table creation fails.
No, there are not any information if this command created table or not. The found variable is updated after query execution - not after DDL command. There is guaranteed so after this command, the table will be or this command fails to an exception.

Should i commit at the end of the procedure which is called by an oracle scheduler job

I am running an oracle JOB which will run a PROCEDURE to CREATE TRUNCATE INSERT DROP some relevant tables.
Is this the best way to do a functionality like this ?
Should I Commit at the end of the procedure or not ?
CREATE OR REPLACE Procedure PR_NAME
IS
BEGIN
CREATE TABLE TABLE_1_BAC AS SELECT * FROM TABLE1_VIA_DBLINK;
TRUNCATE TABLE TABLE_1;
INSERT INTO TABLE_1 SELECT * FROM TABLE_1_BAC;
DROP TABLE TABLE_1_BAC;
--COMMIT;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END;
To create TABLE_1 only once for present data :
CREATE TABLE TABLE_1 AS SELECT * FROM TABLE1_VIA_DBLINK;
and creating an insert trigger for TABLE1_VIA_DBLINK, populating TABLE_1 through this trigger for new datas, and to get rid of this job and procedure seems more feasible.
As you stay in this job, perhaps you'll wait for huge data to be inserted.
By the way, if you insist on using this job, you don't need to issue commit, since and there's already an implicit commit exists inside job mechanism.
What kind of job do you use? JOB or SCHEDULER JOB?
I don't see any reason to DROP/CREATE the table. I don't see any reason why you use the intermediate table at all.
Simply make
CREATE OR REPLACE Procedure PR_NAME
IS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE TABLE_1';
INSERT INTO TABLE_1 SELECT * FROM TABLE1_VIA_DBLINK;
COMMIT;
END;
You don't need any exception handler. In case of JOB you will not see the exception anyway. In case of SCHEDULER JOB you can see exception in views
*_SCHEDULER_JOB_LOG
*_SCHEDULER_JOB_RUN_DETAILS
If you make just this kind of operation you should consider MATERIALIZED VIEW which basically make the same: TRUNCATE and INSERT INTO ... SELECT * FROM ...
No. You don't need to commit.
Those commands are DDL (Data Definition Language) in SQL. So Oracle Database will issue a commit together with the command.
DML (Data Manipulating Language) - like SELECT, UPDATE, INSERT, DELETE requires a commit.
In a scenario, where you will update, delete and insert records. Then you ran a create table command. The records inserted, updated and deleted will be committed (save) to the database.

SQL Triggers in Oracle

My question is as follows:
User name = Admin
Whenever I perform an insert/update/delete operation on a table "a". I need to have a trigger that would insert the username in table "b"
Is that possible?
create or replace trigger audit_a_trg
before insert or update or delete on A
for each row
begin
insert into b values (user);
end;
/
Oracle's online documentation is pretty good. You can read the SQL reference here.
edit
user is a function which returns the name of the account which issues the DML. Find out more.