Can't create trigger using SQLPlus in Oracle - oracle

I'm Learning Oracle and wanted to try creating a trigger. I tried this example form a book in sqlplus.
SQL> CREATE OR REPLACE TRIGGER policy_bull BEFORE insert or update
2 ON emp
3 FOR EACH ROW
4 BEGIN
5 :new.salary := 200;
6 END
7 /
ERROR at line 1:
ORA-04089: cannot create triggers on objects owned by SYS
even though I logged in as SYS using
sqlplus "sys/oracle as sysdba"

You need to type / on a blank line to tell SQLPLUS to run the statement.

Oracle forbids creating triggers on objects owned by SYS.
Did you create the table emp as SYS? You probably want to be a regular user to do that. emp doesn't sound like a system table.

I think a semi-colon is missing after END.
Also mention SYS.emp

SQL> CREATE OR REPLACE TRIGGER policy_bull BEFORE insert or update
2 of SALARY on EMP
3 FOR EACH ROW
4 BEGIN
5 :new.salary := 200;
6 END
7 /
you have to type the column where the "NEW SALARY" is ppl its SALARY so ...or update of SALARY on EMP...

Related

Oracle SELECT <var name> AS <column name> equivalent after stored procedure where <var name> is an outbound parameter (JDBC/SQL Only no SQL*Plus)

Does Oracle have a way other than using using DBMS_OUTPUT to render the content of returned variables coming back out of a stored procedure via SELECT?
I'm aware of functions too, but I don't have a say in rewriting things, in case that's what people are thinking of responding with.
DECLARE
NAME TIDAL.JOBMST.JOBMST_NAME%TYPE; -- Oracle syntax to base the type of variable upon a column in a table. It resolves to varchar2(256)
BEGIN
TIDAL.GETJOBNAMEFORID(1,NAME); -- 'NAME' is an outbound parameter of stored procedure and gets bound to variable 'NAME' in DECLARE above.
DBMS_OUTPUT.PUT_LINE('Name: ' || NAME); -- || is Oracle string concat `+` anywhere else!
END;
The program that processes this SQL via JDBC needs to be able to render output as a CSV, XML or raw payload. It can only do all these options with the "select" style output. (probably using Java's Resultset API)
The DBMS_OUTPUT.PUTLINE doesn't generate output within the program that processes the SQL. DBeaver does. So this doesn't work for me either.
I thought there would be some awkward SELECT :NAME FROM DUAL or SELECT NAME: = NAME INTO DUAL syntax I could use to render it, since Oracle won't allow a SELECT without a FROM akin to SQL Server (see below), but the solution eludes me.
In this case the result is a scalar, but it could equally be one or more records, or rows of a single column..
I would like to use AS in order to be able to label the column(s) for a downstream processes too.
Can someone tell me if this is possible?
The code has to pass JDBC SQL parser syntax checks and generates no ORA error code. The bulk of the solutions I see on Oracle on the internet seem flaky. SQL*Plus answers with things like var or exec or print don't seem to work with JDBC SQL. I've been trying to validate things via DBeaver too - and most of the time a colon prepends variable names it seems to prompt for input so I'm not sure if that/my Oracle knowledge, is muddying the waters and I should try SQL Developer to validate code instead.
This would be the equivalent in SQL Server of what I want to achieve in Oracle:
DECLARE
#NAME varchar(256),
EXEC GETJOBNAMEFORID
1
#NAME = #NAME OUTPUT;
SELECT #NAME As Name
Other that this canned example I don't have visibility to the stored procedures to know if a sys_refcursor is in use on outbound parameters either.
Is it possible? Kind of. This is SQL*Plus (command-line tool):
Procedure with an OUT parameter (just like yours):
SQL> create or replace procedure p_test (par_deptno in dept.deptno%type,
2 par_dname out dept.dname%type)
3 as
4 begin
5 select dname
6 into par_dname
7 from dept
8 where deptno = par_Deptno;
9 end;
10 /
Procedure created.
Declare a variable:
SQL> var v_dname varchar2(20);
Execute the procedure:
SQL> exec p_test(10, :v_dname);
PL/SQL procedure successfully completed.
Print the result:
SQL> print v_dname
V_DNAME
--------------------------------------------------------------------------------
ACCOUNTING
SQL>
What if the procedure returns many rows? Then you could return refcursor:
SQL> create or replace procedure p_test (par_deptno in dept.deptno%type,
2 par_dname out sys_refcursor)
3 as
4 begin
5 open par_dname for
6 select dname
7 from dept
8 where deptno <= par_deptno;
9 end;
10 /
Procedure created.
SQL> var v_dname refcursor
SQL>
SQL> exec p_test(40, :v_dname);
PL/SQL procedure successfully completed.
SQL> print v_dname
DNAME
--------------
ACCOUNTING
RESEARCH
SALES
OPERATIONS
SQL>

Can't create TRIGGER

I need to create a script to delete some data in a database, the table doesn't have the CASCADE constraint and I don't have the right to edit them.
So I'm trying to create a TRIGGER to simulate a Cascade delete on a table (and I will remove it just after the script get executed).
Here is my trigger:
CREATE TRIGGER delete_workspace_on_delete_result
BEFORE DELETE ON RESULT
FOR EACH ROW
BEGIN
DELETE FROM WORKSPACE WHERE workspace_result_id = :old.id;
END;
/
I don't understand why it's not working, I just follow the Oracle documentation but I have this error:
Error report -
ERROR: syntax error at or near "BEGIN"
Position: 87
I'm not used to Oracle but can't find a way to make this work by my own.
I don't see anything wrong, it works. Though:
won't work on Oracle 11g or lower because trigger name is too long (can be max 30 characters)
will work on 12c and above
consider using create or replace; if it exists and you try to create it again, it'll fail
Demo on 11g:
SQL> CREATE TABLE workspace (workspace_result_id NUMBER);
Table created.
SQL> CREATE TABLE result (id NUMBER);
Table created.
SQL> CREATE TRIGGER delete_workspace_on_delete_result
2 BEFORE DELETE
3 ON RESULT
4 FOR EACH ROW
5 BEGIN
6 DELETE FROM WORKSPACE
7 WHERE workspace_result_id = :old.id;
8 END;
9 /
CREATE TRIGGER delete_workspace_on_delete_result
*
ERROR at line 1:
ORA-00972: identifier is too long
SQL> CREATE TRIGGER delete_workspace_on_del_result
2 BEFORE DELETE
3 ON RESULT
4 FOR EACH ROW
5 BEGIN
6 DELETE FROM WORKSPACE
7 WHERE workspace_result_id = :old.id;
8 END;
9 /
Trigger created.
SQL>

Oracle configuration. "create or replace" function create invalid object

I recently moved my database to a new server (both Oracle 11g).
In the new host, there is a weird behavior, that whenever I run something like:
create or replace test_trigger
before insert or update
on test_table
for each row
begin
select 1 from dual;
end;
/
The trigger created is invalid without any error in log. I tried to recompile, it still invalid.
It only happen with the function "create or replace". If I drop the trigger and re-create again, it would be valid.
My question is, did I config something incorrectly? How can I check it? Thank you.
Code you posted won't compile, not in any Oracle database I know. Why? Wrong syntax.
Here's a demonstration:
SQL> create or replace test_trigger
2 before insert or update
3 on test_table
4 for each row
5 begin
6 select 1 from dual;
create or replace test_trigger
*
ERROR at line 1:
ORA-00922: missing or invalid option
SQL> end;
SP2-0042: unknown command "end" - rest of line ignored.
SQL> /
So, what's wrong with it?
create (or replace) wants to know what you're going to create. "test_trigger"? As far as Oracle is concerned, that could be "mickey_mouse" and the result will be the same. It is the trigger keyword that is missing
SELECT in PL/SQL requires an INTO clause, so that you could store the result into something
in order to be able to do that, you have to declare a variable
Here's code that, actually, compiles:
SQL> create or replace trigger test_trigger --> this
2 before insert or update
3 on test_table
4 for each row
5 declare
6 l_dummy number; --> this
7 begin
8 select 1
9 into l_dummy --> this
10 from dual;
11 end;
12 /
Trigger created.
SQL>
So, it seems that you misinterpret reality.

Oracle command to create a table from another schema, including triggers?

Using this command, I am able to create a table from another schema, but it does not include triggers. Is it possible to create a table from another schema, including triggers?
create table B.tablename unrecoverable as select * from A.tablename where 1 = 0;
First option is to run CREATE script for those objects, if you have a code repository. I suppose you don't.
If you use any GUI tool, things are getting simpler as they contain the SCRIPT tab that enables you to copy code from source and paste it into target user.
If you're on SQLPlus, it means that you should, actually, know what you're supposed to do. Here's a short demo.
SQL> connect hr/hr#xe
Connected.
SQL> create table detail (id number);
Table created.
SQL> create or replace trigger trg_det
2 before insert on detail
3 for each row
4 begin
5 :new.id := 1000;
6 end;
7 /
Trigger created.
SQL>
SQL> -- you'll have to grant privileges on table to another user
SQL> grant all on detail to scott;
Grant succeeded.
Connect as SCOTT and check what we've got:
SQL> connect scott/tiger#xe
Connected.
SQL> -- now, query ALL_SOURCE and you'll get trigger code
SQL> set pagesize 0
SQL> col text format a50
SQL> select text from all_source where name = 'TRG_DET' order by line;
trigger trg_det
before insert on detail
for each row
begin
:new.id := 1000;
end;
6 rows selected.
SQL>
Yet another option is to export & import table, which will get the trigger as well (I've removed parts that aren't relevant, as Oracle database version):
C:\>exp hr/hr#xe tables=detail file=detail.dmp
About to export specified tables via Conventional Path ...
. . exporting table DETAIL 0 rows exported
Export terminated successfully without warnings.
C:\>imp scott/tiger#xe file=detail.dmp full=y
. importing HR's objects into SCOTT
. importing HR's objects into SCOTT
. . importing table "DETAIL" 0 rows imported
Import terminated successfully without warnings.
C:\>
Check what's imported (should be both table and trigger):
SQL> desc detail
Name Null? Type
----------------------------------------- -------- ---------------
ID NUMBER
SQL> select * From detail;
no rows selected
SQL> insert into detail (id) values (-1);
1 row created.
SQL> select * From detail;
ID
----------
1000
SQL>
Cool; even the trigger works.
There might be some other options, but these 4 should be enough to get you started.

Update using the table list

I am facing an issue while updating 100 tables. Problem is as below:
I have to update 299 columns in 100 tables and for that I have to create one oracle procedure. I have created a table with two columns where I am storing the table name and the columns for e.g.:
lookup_table:------
table_name column_name
Now what I want to do is pick every row and update the cols based on table name, hence I need to use the table_name and column_name as variables.
Let me know if anyone worked on this type of scenario.
For such dynamic operations, you need to (ab)use EXECUTE IMMEDIATE in PL/SQL. In SQL, you cannot use object names dynamically, it must be static.
I would suggest to do it in SQL and prepare the required update statements. Using a good text editor it shouldn't be a difficult task.
But, if you still want to do it in PL/SQL, then you need to first build the sql statements dynamically and then use EXECUTE IMMEDIATE.
For example,
SQL> set serveroutput on
SQL> DECLARE
2 var_sql VARCHAR2(1000);
3 var_tab VARCHAR2(10);
4 var_ename VARCHAR2(10);
5 BEGIN
6 var_tab:= 'EMP';
7 var_sql :='SELECT empno FROM '||var_tab||' WHERE empno=7369';
8 EXECUTE IMMEDIATE var_sql INTO var_ename;
9 DBMS_OUTPUT.PUT_LINE('Employee name is '||var_ename);
10 END;
11 /
Employee name is 7369
PL/SQL procedure successfully completed.
SQL>

Resources