I've made a trigger in SQL and need him to write an output after inserting a new row in the table. Please see the example:
CREATE OR REPLACE TRIGGER GAS_CODES AFTER
INSERT ON blablatable
FOR EACH ROW
BEGIN
insert into blabla2table (...,...,...,...)
values (:new...,...,...,..);
---output:
dbms_output.put_line('New row has been added.');
END;
/
When I compile the trigger, it shows in the Script Output, but if I add a new row into the table, there's nothing.
You are missing SET SERVEROUTPUT ON. This command is understandable also by SQLDeveloper.
Let's do a quick test inside the SQLDeveloper.
CREATE USER "TEST_SCHEMA" IDENTIFIED BY "TEST";
User "TEST_SCHEMA" created.
GRANT UNLIMITED TABLESPACE TO "TEST_SCHEMA";
Grant succeeded.
CREATE TABLE "TEST_SCHEMA"."NAMES" ("ID" NUMBER, "NAME" VARCHAR2(25), PRIMARY KEY("ID"));
Table "TEST_SCHEMA"."NAMES" created.
CREATE OR REPLACE TRIGGER "TEST_SCHEMA"."NAMES_TRG_1" AFTER
INSERT ON "TEST_SCHEMA"."NAMES"
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('New row has been added.');
END;
/
Trigger NAMES_TRG_1 compiled
SET SERVEROUTPUT ON
This command won't print anything in SQL Developer. No worries here.
INSERT INTO "TEST_SCHEMA"."NAMES" VALUES (1, 'Mark Smith');
1 row inserted.
New row has been added.
As you can see, the output was there and it was inserted after the actual row was inserted into the table. Works fine.
To cleanup the testcase, run this:
DROP USER "TEST_SCHEMA" CASCADE;
EDIT 1:
When you are working with Table Data Editor, this is behaving differently. Table Data Editor has its own Oracle session and it has different way of capturing DBMS Output.
To open the DBMS capture window, you need to click on "VIEW" menu and select "DBMS Output" option.
Then click the green plus button and set the database, that will be captured.
Now you can see the output.
Beware as the output here is not "realtime", this window will show something only when there is a buffer flush, and the buffer flush cannot be invoked manually/directly.
Most likely the client (SQLDeveloper) doesn't read the output buffer.
To enable this you must choose from menu "view" -> "dbms output" and then click the green "+" in the dbms output window to read the output buffer for your connection ...
In sqlplus you can do it like this:
SQL> drop table tst purge;
Table dropped.
SQL> drop table tst2 purge;
Table dropped.
SQL> create table tst ( tst_no integer);
Table created.
SQL> create table tst2 ( tst_no integer);
Table created.
SQL> create or replace trigger tst_trg after insert on tst
for each row
begin
insert into tst2 (tst_no) values (:new.tst_no);
dbms_output.put_line('new row with tst_no='|| :new.tst_no);
end;
/ 2 3 4 5 6 7
Trigger created.
SQL> set serveroutput on;
exec dbms_output.enable;
insert into tst values (1); SQL>
PL/SQL procedure successfully completed.
SQL> SQL>
new row with tst_no=1
1 row created.
SQL> r
1* insert into tst values (1)
new row with tst_no=1
1 row created.
SQL> select * from tst2;
TST_NO
----------
1
1
SQL>
as you can see the output is read and printed in sqlplus, and rows are inserted into the target table tst2
hope it helps...
Related
Guys I am using oracle 11g and I am pretty new with it.
the problem is when I try to create a table and insert a value in sqlplus terminal, it is not showing in the Navicat lite(Graphical representation software).
Here, let me make this more clear by showing you the pictures.
here are the rows that are getting printed on SQLPlus terminal
But take a look at the rows in the Navicat
Here the table name is TIME.
Can anyone explain to me what is the problem?
Looks like you didn't
commit;
in SQL*Plus after inserting rows. Unless you do that, those values are visible only to you, but not other sessions (which is what Navicat sees). So - commit.
As of letter case and double quotes:
This is how you should be doing it - don't use double quotes, reference tables any way you want:
SQL> create table test (id number);
Table created.
SQL> insert into test (id) values (1);
1 row created.
SQL> select * from test;
ID
----------
1
SQL> select * from TEST;
ID
----------
1
SQL> select * from tEsT;
ID
----------
1
SQL> drop table test;
Table dropped.
If you use double quotes, you have to reference the table exactly the same way as you created it:
SQL> create table "test" (id number);
Table created.
SQL> insert into test (id) values (1);
insert into test (id) values (1)
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> insert into TEST (id) values (1);
insert into TEST (id) values (1)
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> insert into "TEST" (id) values (1);
insert into "TEST" (id) values (1)
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> insert into "test" (id) values (1);
1 row created.
SQL>
I have created a user (say DROP_PARTITION_USER) to drop partitions of a table. The table is owned by different user (say NORMAL_USER).
Currently, I have granted DROP ANY TABLE and ALTER ANY TABLE privileges to DROP_PARTITION_USER. When DROP_PARTITION_USER executes following statement, it gets executed successfully.
ALTER TABLE SCHEMANAME.TABLENAME DROP PARTITION <PARTITION_NAME> UPDATE GLOBAL INDEXES;
But, DROP ANY TABLE and ALTER ANY TABLE allows DROP_PARTITION_USER to drop and alter any table under any schema [https://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9013.htm ].
Is there any way in Oracle to restrict drop and alter table under specific schema?
The common way to solve this is to create a procedure owned by NORMAL_USER to drop one of the partitions of one of it's tables.
Then you GRANT EXECUTE on this procedure to DROP_PARTITION_USER.
You'll need no extra privileges.
CREATE OR REPLACE PROCEDURE my_drop_partition (p_table_name VARCHAR2, p_partition_name VARCHAR2)
IS
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE '||p_table_name||' DROP PARTITION '||p_partition_name;
END my_drop_partition;
/
GRANT EXECUTE ON my_drop_partition TO drop_partition_user;
You can use a DDL trigger to capture such attempts and take whatever action you like. For example
SQL> CREATE OR REPLACE TRIGGER STOP_THAT_STUFF
2 before create or alter or drop on database
3 begin
4 if ora_dict_obj_owner in ('SCOTT') and
5 ora_sysevent in ('DROP','ALTER') and
6 ora_dict_obj_name = 'MY_TABLE'
7 then
8 raise_application_error(-20000,'What the hell are you thinking!!!!');
9 end if;
10 end;
11 /
Trigger created.
SQL>
SQL> conn scott/tiger
Connected.
SQL> create table scott.my_table(x int );
Table created.
SQL> create table scott.my_other_table(x int);
Table created.
SQL> drop table my_other_table;
Table dropped.
SQL> drop table my_table;
drop table my_table
*
ERROR at line 1:
ORA-04088: error during execution of trigger 'SYS.STOP_THAT_STUFF'
ORA-00604: error occurred at recursive SQL level 1
ORA-20000: What the hell are you thinking!!!!
ORA-06512: at line 6
SQL> desc my_table
Name Null? Type
----------------------------------------------------------------------- -------- ----------------
X NUMBER(38)
If I execute the following script in SQLPlus:
CREATE TABLE trailing_spaces (text VARCHAR2(100))
/
-- Note that there is a blank space after 'one' and 'two'
INSERT INTO trailing_spaces (text) VALUES ('one
two
three')
/
COMMIT
/
SQLPlus automatically trims the lines and removes the trailing spaces, so that instead of inserting the value one two three is inserting onetwothree.
Does anyone know how to keep SQLPlus from trimming those lines and execute the script as it is?
You can do it as in SQLPLUS :
SQL> CREATE TABLE trailing_spaces (text VARCHAR2(100));
Table created.
SQL> INSERT INTO trailing_spaces (text) VALUES ('one'||' '||
'two'||' '||
'three') ;
1 row created.
SQL> COMMIT;
Commit complete.
SQL> SELECT * FROM TRAILING_SPACES;
TEXT
--------------------------------------------------------------------------------
one two three
If I execute your insert statement, I get the text on three different lines. How could you get the text in one line as onetwothree? I am using Oracle 11.2.0.4
In my case, if I cannot alter the script, I can run the existing script and manipulate it during the selection as shown below.
SQL> insert into tbl1 values('one
2 two');
1 row created.
SQL> insert into tbl1 values('three
2 four');
1 row created.
SQL> select * from tbl1;
TEXT
--------------------
one
two
three
four
SQL> select REPLACE(REPLACE(text, CHR(10)), CHR(13)) as text from tbl1;
TEXT
--------------------
one two
three four
I am using before update trigger for each row on table, say emp_table to update one column modifid_date before loading into table. If I am going to update the table with same/existing values of a row, then is this trigger going to fire or not?
condition in trigger:
:new.modifid_dt := sysdate;
Table Values before update: john (name),4867 (id),20-04-2016 (modifid_dt)
Table values now going to update: john (name),4867 (id)
Your trigger will be fired, no matter the values you are using; for example:
SQL> create table testTrigger ( a number)
2 /
Table created.
SQL> CREATE OR REPLACE TRIGGER before_update_trigger
2 before update on testTrigger
3 for each row
4 begin
5 dbms_output.put_line('Trigger fired!');
6 end;
7 /
Trigger created.
SQL> insert into testTrigger values (10);
1 row created.
SQL>
SQL>
SQL> update testTrigger set a = 10;
Trigger fired!
1 row updated.
SQL> update testTrigger set a = 11;
Trigger fired!
1 row updated.
SQL>
If you want avoid "false" firing you should write trigger like this:
create or replace trigger trigger1
before update on tst
for each row
begin
IF :new.t_key != :old.t_key AND ... THEN
dbms_output.put_line('Trigger fired!');
END IF;
end;
But beware of NULL values, of course.
New or existing values - no matter, anyway you'll perform an update so trigger will fire.
Is possible to create or replace a view inside a trigger in Oracle?
The view is created by joining 2 tables and one of them is the one updated by the trigger
Just to provide all options (however weird the idea of creating a view inside a trigger might be...) you can create a view in a trigger. Yes, an implicit COMMIT will follow, but if we make the trigger work in autonomous transaction, then the dynamic DDL will not fail. Using Luke Woodward's example:
CREATE TABLE test (a integer);
INSERT INTO test (a) VALUES (5);
CREATE OR REPLACE TRIGGER test_trig
AFTER UPDATE ON test
FOR EACH ROW
DECLARE
-- making the trigger work outside of the main transaction
PRAGMA autonomous_transaction;
BEGIN
EXECUTE IMMEDIATE 'CREATE OR REPLACE VIEW test_view AS SELECT * FROM test';
END;
/
UPDATE test SET a = 6;
SELECT * FROM test_view;
A
----------
6
Check at SQLFiddle
No, you can't. Creating a view forces a commit, and you cannot commit in a trigger.
Here's what happens when you try to do this:
SQL> CREATE TABLE test (a integer);
Table created.
SQL> INSERT INTO test (a) VALUES (5);
1 row created.
SQL> COMMIT;
Commit complete.
SQL> CREATE OR REPLACE TRIGGER test_trig
2 AFTER UPDATE ON test
3 FOR EACH ROW
4 BEGIN
5 EXECUTE IMMEDIATE 'CREATE OR REPLACE VIEW test_view AS SELECT * FROM test';
6 END;
7 /
Trigger created.
SQL> UPDATE test SET a = 6;
UPDATE test SET a = 6
*
ERROR at line 1:
ORA-04092: cannot COMMIT in a trigger
ORA-06512: at "LUKE.TEST_TRIG", line 2
ORA-04088: error during execution of trigger 'LUKE.TEST_TRIG'