Adding through view trigger error - oracle

I have this view and the instead of trigger for inserting through view
CREATE VIEW LivrareNoua AS
Select numef,numec,numep,cantitate
From Furnizori F, Componente C, Proiecte P, Livrari L
Where F.idf = L.idf AND C.idc = L.idc AND P.idp = L.idp;
I don't know what the problem might be
create or replace TRIGGER triggerinstead
INSTEAD OF INSERT ON LivrareNoua
FOR EACH ROW
BEGIN
INSERT INTO Furnizori(idf,numef) VALUES('&idf',:new.numef);
INSERT INTO Componete(idc,numec) VALUES('&idc',:new.numec);
INSERT INTO Proiecte(idp,numep) VALUES('&idp',:new.numep);
INSERT INTO Livrari(idf,idc,idp,cantitate) VALUES('&idf','&idc','&idp',:new.cantitate);
END;
ERRORS:
3 13 PL/SQL: ORA-00942: table or view does not exist
3 1 PL/SQL: SQL Statement ignored

make sure that the development schema is the same as the schema of the view

Related

EFCore error:- ORA-00904: "m"."Id": invalid identifier

I am working with an application using asp.net core 2.2 and efcore database first approach with Oracle database. I am using Oracle.EntityFrameworkCore (2.19.60) nuget package, successfully mapped db model, but when I try to fetch data from DBContext , getting error
ORA-00904: "m"."Id": invalid identifier
Oracle Database version: Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production
code:
var fetched = await myDatabaseContext.MyTableVersions.ToListAsync();
LinQ is generating following query :
SELECT "m"."Id", "m"."MAJORVERSION" FROM "MyTableVersions" "m"
Since It's not a correct syntax for PL/Sql query so getting error ORA-00904: "m"."Id": invalid identifier.
Is there any way to fix this error? Thanks.
I have searched on the web and found
Bug 30352492 - EFCORE: ORA-00904: INVALID IDENTIFIER
but that issue is related to schema.
The query is perfectly valid (db<>fiddle here), assuming your table looks something like
CREATE TABLE "MyTableVersions"
("Id" NUMBER,
MAJORVERSION NUMBER)
However, I suspect your table looks like
CREATE TABLE "MyTableVersions"
(ID NUMBER,
MAJORVERSION NUMBER)
I don't know what the class looks like that you're trying to fetch into, but I suspect it has a field named Id. If you can change the name of that field to ID (in other words, so that its capitalization matches the capitalization of the related database column) you might find it works then.
Double quotes are something you should avoid in Oracle world.
Your query:
SELECT "m"."Id", "m"."MAJORVERSION" FROM "MyTableVersions" "m"
means that column name is exactly Id (capital I followed by d). Only if that's really so, you should use double quotes. Otherwise, simply remove them:
SELECT m.id, m.MAJORVERSION FROM MyTableVersions m
The same goes for the table name - if it was created using mixed case (and you can't do that without double quotes), you'll have to use double quotes and exactly same letter case always. Otherwise, don't use them.
Oracle is case-insensitive regarding object and column names and are UPPERCASE by default:
SQL> create table test (id number);
Table created.
SQL> desc test
Name Null? Type
----------------------------------------- -------- -----------------
ID NUMBER
SQL> select table_name, column_name
2 from user_tab_columns
3 where table_name = 'TEST';
TABLE_NAME COLUMN_NAME
------------------------------ ------------------------------
TEST ID
SQL> insert into test (id) values (1);
1 row created.
SQL>
But, if you use mixed case with double quotes, then use them always:
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-00904: "ID": invalid identifier
SQL> insert into "teST" ("Id") values (1);
1 row created.
SQL>
So: first make sure what table and column names really are, then use them appropriately.
To avoid problems with case-sensitivity, add the option to eliminate EF to add quotes to the generated queries. For instance, if you are using Devart Oracle provider, this is done in the following way:
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpDbContextOptions>(options =>
{
var config = Devart.Data.Oracle.Entity.Configuration.OracleEntityProviderConfig.Instance;
config.Workarounds.DisableQuoting = true;
...
}
}
If you are using official provider - just inherit from DbCommandInterceptor (do quotes replacement with empty character in dbCommand in ...Executing methods), add this interceptor to DbContextOptionsBuilder instance.

SQL Trigger error (ORA-00942: table or view does not exist)

I create this sql trigger:
CREATE OR REPLACE TRIGGER create_event_from_task BEFORE INSERT ON llx_projet_task
BEGIN
INSERT INTO llx_actioncomm (priority, fulldayevent, location, label, fk_element, elementtype, fk_project, datep, datef, percentage, note)
SELECT 0, 0, '', 'prova', id, 'project_task', fk_project, date_start, date_end, progress, description
FROM inserted;
END;
/
But when I execute says this errors:
Errors: TRIGGER CREATE_EVENT_FROM_TASK
Line/Col: 2/2 PL/SQL: SQL Statement ignored
Line/Col: 4/7 PL/SQL: ORA-00942: table or view does not exist
Can anyone help me?
I think it got this error because of the select query inside the trigger. Check if the user which called the trigger has the grant to execute select from the "inserted" table.
https://www.tekstream.com/resource-center/ora-00942-table-or-view-does-not-exist/
Ora-00942 means you are attempting to execute an SQL statement that references a table or view which does not exist. There are several possible causes for the “table or view does not exist” error, including:
1) Referencing a table or view that does not exist
2) Using an unauthorized synonym
3) Using an expression of view where a table is required
4) Attempting to use a table without proper permission or privilege
inserted is part of SQL Server. I think you want:
BEGIN
INSERT INTO llx_actioncomm (priority, fulldayevent, location, label, fk_element, elementtype, fk_project, datep, datef, percentage, note)
SELECT 0, 0, '', 'prova', :new.id, 'project_task',
:new.fk_project, :new.date_start, :new.date_end,
:new.progress, :new.description
FROM dual;
END;

ORA-04091 (mutating table) only if specific field is filled

Got a table, which has a key on itself:
+----+-----------+-----------+
+ ID + ID_PARENT + IS_PARENT +
+----+-----------+-----------+
+ 1 + (null) + 0 +
+ 2 + (null) + 1 +
+ 3 + 2 + 0 +
+----+-----------+-----------+
As you see, ID 1 is on its own, 3 is a child of 2.
Now I want to have a trigger, that on INSERT/UPDATE ...
errors, if an inserted row is it's own parent (not possible)
if it has an ID_PARENT, set the parent's IS_PARENT to 1
This is my approach:
CREATE OR REPLACE TRIGGER tri_table_set_parent
BEFORE
INSERT OR UPDATE ON table
FOR EACH ROW
WHEN ( new.id_parent IS NOT NULL )
BEGIN
IF :new.id = :new.id_parent
THEN
RAISE_APPLICATION_ERROR(-20666, 'A gap cant be the parent of itself. More information here: https://youtu.be/hqRZFWE1X_A');
END IF;
UPDATE table
SET is_parent = 1
WHERE id = :new.id_parent;
END;
/
The error works as intended, woohoo! But now when inserting, I have problems.
When inserting a row without ID_PARENT, it works (because trigger won't trigger at all).
Inserting a row, whose parent's ID_PARENT = (null):
INSERT INTO table (ID, ID_PARENT) VALUES (4, 1);
-> Works!
But inserting a row, whose parent got an ID_PARENT:
INSERT INTO table (ID, ID_PARENT) VALUES (5, 3);
-> Errors:
ORA-04091: Tabelle TABLE wird gerade geändert, Trigger/Funktion sieht dies möglicherweise nicht
ORA-06512: in "TRI_TABLE_SET_PARENT", Zeile 6
ORA-04088: Fehler bei der Ausführung von Trigger "TRI_TABLE_SET_PARENT"
ORA-06512: in "TRI_TABLE_SET_PARENT", Zeile 6
ORA-04088: Fehler bei der Ausführung von Trigger "TRI_TABLE_SET_PARENT"
Updating the table doesn't work at all, same error.
Ok, so I understand that I can't select stuff that might be changed simultaniously. But I'm updating, and also I'm checking that I don't reference the same rows.
So what am I missing?
The evil thing in relational database is redundancy which you try to introduce.
More correct relational approach would be to define the table without the IS_PARENT column.
select * from my_parent order by id;
ID ID_PARENT
---------- ----------
1
2
3 2
... and add the redundant column in an access view
create view V_MY_PARENT as
select a.ID, a.ID_PARENT,
case when exists (select null from my_parent where ID_PARENT = a.ID) then 1 else 0 end as IS_PARENT
from my_parent a
order by a.ID;
To get all non parents you access the view
select * from V_MY_PARENT
where is_parent = 0;
ID ID_PARENT IS_PARENT
---------- ---------- ----------
1 0
3 2 0
If you want to materialize the redundancy (e.g. for performance reasons) use MATERIALIZED VIEWs.
With this approach you will not end with parents classified as no parents or vice versa, which is quite possible in your design.
The error cause is that you are updating row that you didn't inserted yet.
you could update the data you are inserting using :new keyword.
so the solution will be replacing the update statement with
:new.is_parent := 1
ORA-04091 (table is mutating, trigger may not see it) occurs here because you have a BEFORE trigger defined on "TABLE", and in the body of the trigger you're attempting to update "TABLE". Oracle doesn't allow this as it can lead to a trigger loop (i.e. if this was allowed your program could execute a statement which causes the trigger to fire; within the body of the trigger a statement executes which causes the trigger to fire; within the body of the trigger a statement executes which causes the trigger to fire; within the body of the trigger a statement executes which causes the trigger to fire; within the body of the trigger a statement executes which causes the trigger to fire; etc). So you're not allowed to do this in a BEFORE trigger. The simplest fix is to change the trigger to an AFTER trigger. In other words, change BEFORE INSERT OR UPDATE ON table to AFTER INSERT OR UPDATE ON table. In this particular case it doesn't appear this would be a problem, but I don't know what constraints you have on your table which might make this unacceptable. Give it a try.
Just Replace
UPDATE "table"
SET id_parent = 1
WHERE id = :new.id_parent;
with
if :old.id = :new.id_parent and updating then
:new.id_parent := 1;
end if;
e.g avoid using a DML within the same "table" against ORA-04091.
P.S. being table as a reserved keyword, I replaced with "table".

create trigger to save CONSTRAINTs changes on tables in oracle

I want to create table to save all CONSTRAINTs changes in my oracle database,
so i have created this table(table name , constraint name , date , mode like [insert|update|delete] )
CREATE TABLE CONS
(
C_ID NUMBER NOT NULL
, C_NAME VARCHAR2(50) NOT NULL
, T_NAME VARCHAR2(50) NOT NULL
, EXE_DATE DATE NOT NULL
, MODE VARCHAR2(50) NOT NULL
);
the problem was by insert data,
I was thinking of creating trigger on user_cons_columns after insert or update or delete,
but I found that user_cons_columns is a view and i can't create trigger on it,
so how can I do this work?
or what is the tables that I can create trigger on it to do this???
thanks .......
User_Cons_Columns is metadata view in oracle and you can not use it for monitoring constraint changes.
I think, You can use this metadata view :
SELECT *
FROM ALL_CONSTRAINTS T
It shows which constraint has changed by LAST_CHANGE Column and other data that you can use them.
I don't know if we can create DML TRIGGERs on data dictionary tables in Oracle, but that sounds like a bad idea.
My suggestion to you would be to create a DDL Trigger on the ALTER event
Firstly, as a one time activity, you could store all the available constraints in your CONS table.
Then in your trigger, you could use these conditions to check if a table and column was altered.
if (ora_sysevent = 'ALTER' and
ora_dict_obj_type = 'TABLE')
then alter_column :=
ora_is_alter_column('FOO');
end if;
You could then query the user_cons_columns , ALL_CONSTRAINTS and CONS - whichever you find is relevant to store your data - to find if a new constraint was added or not. If it was indeed added or modified, make an entry into CONS or else update it ( using MERGE statement )
As you said, you can't create that type of a trigger on USER_CONS_COLUMNS:
SQL> create or replace trigger trg_myucc
2 before insert
3 on user_cons_columns
4 begin
5 null;
6 end;
7 /
create or replace trigger trg_myucc
*
ERROR at line 1:
ORA-25001: cannot create this trigger type on this type of view
Why wouldn't we try INSTEAD OF TRIGGER?
SQL> create or replace trigger trg_myucc
2 instead of insert
3 on user_cons_columns
4 for each row
5 begin
6 null;
7 end;
8 /
on user_cons_columns
*
ERROR at line 3:
ORA-01031: insufficient privileges
OK, that won't work either. But, what prevents us on creating a view upon a view, and then create INSTEAD OF trigger on that newly created view?
SQL> create or replace view my_ucc as select * from user_cons_columns;
View created.
SQL> create or replace trigger trg_myucc
2 instead of insert
3 on my_ucc
4 for each row
5 begin
6 null;
7 end;
8 /
Trigger created.
Fine; now you have a way to do what you're supposed to do. More about triggers here.

How can I solve the mutating table error here?

set serveroutput on;
CREATE OR REPLACE TRIGGER hw3
BEFORE DELETE on ENROLLS
for EACH ROW
ENABLE
DECLARE
v_sid number;
v_term varchar2(20);
v_sectno number;
v_COMPNAME varchar2(20);
v_points number;
BEGIN
select :old.SID,:old.TERM,:old.SECTNO into v_sid,v_term,v_sectno from enrolls;
select COMPNAME,points into v_compname,v_points from scores
where scores.sid=v_sid and scores.term=v_term and scores.sectno=v_sectno;
INSERT into DELETED_SCORES (SID,TERM,SECTNO,compname,points)
values (v_sid,v_term,v_sectno,v_compname,v_points);
DELETE FROM SCORES
WHERE SID=V_SID AND TERM=V_TERM AND SECTNO=V_SECTNO;
END;
/
There are two table, which is enrolls and scores. And SCORES table has a combined foreign keys including SID,TERM,AND SECTNO referring to table ENROLLS.
The trigger is now successfully compiled, but there is a problem shown as below:
Error starting at line : 24 in command -
DELETE FROM enrolls
WHERE SID=1111 and term='F12' and sectno=1031
Error report -
SQL Error: ORA-04091: table C16_HE_JIEL.ENROLLS is mutating, trigger/function may not see it
ORA-06512: at "C16_HE_JIEL.HW3", line 8
ORA-04088: error during execution of trigger 'C16_HE_JIEL.HW3'
04091. 00000 - "table %s.%s is mutating, trigger/function may not see it"
*Cause: A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
*Action: Rewrite the trigger (or function) so it does not read that table.
never use before trigger for DML. In some situations before trigger can be fired more than once for the same row. It might happen in situations when your session is blocked by other session updating/deleting the same row.
Use compound trigger and apply DML changes in after trigger session.
Then you can be sure, that data you see are really correct.
The mutating table error means that Oracle can not quarantee that what you're doing is deterministic.
This select:
select :old.SID,:old.TERM,:old.SECTNO into v_sid,v_term,v_sectno from enrolls;
Is invalid for two reasons:
you can't select from the table where the trigger fired on
you are selecting all rows from that table, not just one.
The select isn't needed anyway, you can simply use the values in the OLD record directly (and remove the invalid select ... from enrolls)
select COMPNAME,points
into v_compname,v_points
from scores
where scores.sid = :old.SID
and scores.term = :old.TERM
and scores.sectno = :old.SECTNO;
The above statement requires that the combination of (sid, term, secno) is unique in the table scores. If that is not the case and you need to insert multiple rows with into deleted_scores you need to use an INSERT based on a select.
Which then removes the need for variables completely. So the whole trigger can be simplified to:
CREATE OR REPLACE TRIGGER hw3
BEFORE DELETE on ENROLLS
for EACH ROW
BEGIN
INSERT into DELETED_SCORES (SID,TERM,SECTNO,compname,points)
select sid, term, sectno, compname, points
from scores
where scores.sid = :old.SID
and scores.term = :old.TERM
and scores.sectno = :old.SECTNO;
DELETE FROM SCORES
WHERE SID = :OLD.sid
AND TERM = :OLD.term
AND SECTNO = :OLD.sectno;
END;
/
More details about the "table is mutating" restriction can be found in the manual:
http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS759

Resources