I get an ORA-00903 when merging into an otherwise updatable view in Oracle 11gR2 (USER_UPDATABLE_COLUMNS shows all columns insertable, updatable, deletable for base and view)
Standard Insert, Update, Delete all work normally.
The docs:
http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_9016.htm#SQLRF01606
has the following:
Use the INTO clause to specify the target table or view you are
updating or inserting into. In order to merge data into a view, the
view must be updatable. Refer to "Notes on Updatable Views" for more
information.
The updatable view criteria appear to be met in the following example, but the ORA-00903 is present in all merge attempts. Changes to the instead of trigger don't appear to have any impact on mergability.
CREATE TABLE MERGE_TEST_B
(MERGE_TEST_ID NUMBER NOT NULL PRIMARY KEY,
MERGE_TEST_DESC VARCHAR2(50) UNIQUE NOT NULL);
CREATE OR REPLACE VIEW MERGE_TEST_V
AS
SELECT
MERGE_TEST_B.MERGE_TEST_ID,
MERGE_TEST_B.MERGE_TEST_DESC
FROM MERGE_TEST_B;
CREATE OR REPLACE TRIGGER MERGE_TEST_V_TIX
INSTEAD OF INSERT OR UPDATE OR DELETE ON MERGE_TEST_V
FOR EACH ROW
BEGIN
DBMS_OUTPUT.PUT_LINE('TESTING VIEW MERGE.');
END;
/
I wondered if there is a change that can can get this view into a mergable state, or whether this is ineligible.
The following attempt fails:
MERGE INTO MERGE_TEST_V
USING
(SELECT
'TESTMERGE' MERGE_TEST_DESC
FROM DUAL) TEST_DATA
ON (MERGE_TEST_V.MERGE_TEST_DESC = TEST_DATA.MERGE_TEST_DESC)
WHEN NOT MATCHED THEN INSERT
(MERGE_TEST_ID, MERGE_TEST_DESC)
VALUES
(-100, TEST_DATA.MERGE_TEST_DESC);
Any ideas would be appreciated.
Thanks
I'm not sure why Oracle returns ORA-00903 instead of ORA-38106, but the issue appears to be your trigger. Dropping the trigger will allow your merge to work.
According to the description of ORA-38106, "When using MERGE to modify a view, you must only specify a single table in the view, and the view cannot have an INSTEAD OF trigger." [emphasis mine]
Almost buried in the documentation on the merge statement, this is actually mentioned
Related
I have one requirement that I have to get the list of triggers associated to the given table/view.
Can anyone help me to find the triggers for a table in PostgreSQL?
This will return all the details you want to know
select * from information_schema.triggers
or if you want to sort the results of a specific table then you can try
SELECT event_object_table
,trigger_name
,event_manipulation
,action_statement
,action_timing
FROM information_schema.triggers
WHERE event_object_table = 'tableName' -- Your table name comes here
ORDER BY event_object_table
,event_manipulation
the following will return table name that has trigger
select relname as table_with_trigger
from pg_class
where pg_class.oid in (
select tgrelid
from pg_trigger
)
The problem with the view information_schema.triggers (besides being slow) is, per documentation:
The view triggers contains all triggers defined in the current
database on tables and views that the current user owns or has some
privilege other than SELECT on.
Meaning, you only get to see triggers you have appropriate privileges on.
To see all triggers for a table, look in the system catalog pg_trigger
SELECT tgname
, tgisinternal, pg_get_triggerdef(oid) AS definition -- optional additions
FROM pg_trigger
WHERE tgrelid = 'myschema.mytbl'::regclass; -- optionally schema-qualified
I added tgisinternal to show which are internal triggers, and pg_get_triggerdef(oid) to get the definition (mostly relevant for non-internal triggers).
Works for tables and views.
Or you could use a GUI like pgAdmin that displays the list under the table node in the object browser.
On psql command-line tool you can also use \dS <table_name> (from https://serverfault.com/questions/331024/how-can-i-show-the-content-of-a-trigger-with-psql)
select tgname
,relname
,tgenabled
,nspname from pg_trigger
join pg_class on (pg_class.oid=pg_trigger.tgrelid)
join pg_namespace on (nspowner=relowner);
tgenabled (To check if its disabled)
O = trigger fires in "origin" and "local" modes,
D = trigger is disabled,
R = trigger fires in "replica" mode,
A = trigger fires always.
I noticed that infoschema does NOT contain key relation table information about triggers (at least in postgres 10). pg_triggers does contain this info. Also noticed that datagrip will not script relation tables when you script the triggers, so i'm assuming that it uses infoschema to script them (and then your table would be missing the relation tables, and the trigger functions referencing them would fail). PG documentation says that columns in infoschema for action_reference_old_table applies to a feature not available in postgres(10), but i'm definitely using them, and they definitely show up in pg_triggers. FYI.
\df will list all the functions including triggers.
\dft will list all the triggers.
I have create view without any problem in Oracle. But I can not update it.I want update view in oracle, please help. Is it possible anyway?
You can create an instead of trigger on the view, as described in the documentation:
A view presents the output of a query as a table. If you want to change a view as you would change a table, you must create INSTEAD OF triggers. Instead of changing the view, they change the underlying tables.
Once you have that trigger in place, you can update the view using the same syntax as if it was a table.
You haven't shown your view or table definitions so there isn't enough information to provide a useful example; fortunately the documentation has one you can use as a starting point.
View is a select of your table my friend, there for if you want to update your view you must update your table and then you will see the changes in your view.
I want users to SELECT and Modify Data trough a view, but give no permissions to the base table.
SELECTing Data trough a View works fine.
But when I want to INSERT, UPDATE or DELETE data through a view, SQL Server says that there are missing permissions on the base table.
Following objects:
Table, named: dbo.test
View, named: dbo.vw_test
The table has two columns:
Column_1 IDENTITY....
Column_2 int (updateable column)
The view has following statement:
SELECT * FROM dbo.test;
I have created a LOGIN and a USER on this database with SELECT, INSERT, UPDATE, DELETE permissions on this view. There is no DENY on the base table.
As said, SELECT works, but updating Column_2 not.
Why? Do I need to grant all rights to the base table?
I hopefully think not. I already have created an INSTEAD OF INSERT trigger on the view to test it. But it doesn't work.
What can I do, to modify data trough a view?
I guess that you've misunderstood views. If you are modifying data inside a view it means that you are directly accessing all tables that exist into the SQL statement defining that View. This means that if you want to modify data, modifications will be done directly to all tables that are represented by that view, which at the end means that you have to give enough permissions in order to be able to perform those kind of actions. Please see the reference in this link (section Before you begin -> permissions).
I have a dozen tables of whom I want to keep the history of the changes. For every one I created a second table with the ending _HISTO and added fields modtime, action, user.
At the moment before I insert, modify or delete a record in this tables I call ( from my delphi app ) a oracle procedure that copies the actual values to the histo table and then do the operation.
My procedure generates a dynamic sql via DBA_TAB_COLUMNS and then executes the generated ( insert into tablename_histo ( fields s ) select fields, sysdate, 'acition', userid from table_name
I was told that I can not call this procedure from a trigger because it has to select the table the trigger is triggered on. Is this true ? Is it possible to implement what I need ?
Assuming you want to maintain history using triggers (rather than any of the other methods of tracking history data in Oracle-- Workspace Manager, Total Recall, Streams, Fine_Grained Auditing etc.), you can use dynamic SQL in the trigger. But the dynamic SQL is subject to the same rules that static SQL is subject to. And even static SQL in a row-level trigger cannot in general query the table that the trigger is defined on without generating a mutating table exception.
Rather than calling dynamic SQL from your trigger, however, you can potentially write some dynamic SQL that generates the trigger in the first place using the same data dictionary tables. The triggers themselves would statically refer to :new.column_name and :old.column_name. Of course, you would have to either edit the trigger or re-run the procedure that dynamically creates the trigger when a new column gets added. Since you, presumably, need to add the column to both the main table and the history table, however, this generally isn't too big of a deal.
Oracle does not allow a trigger to execute a SELECT against the table on which the trigger is defined. If you try it you'll get the dreaded "mutating table" error (ORA-04091), and while there are ways to get around that error they add a lot of complexity for little value. If you really want to build a dynamic query every time your table is updated (IMO this is a bad idea from the standpoint of performance - I find that metadata queries are often slow, but YMMV) it should end up looking something like
strAction := CASE
WHEN INSERTING THEN 'INSERT'
WHEN UPDATING THEN 'UPDATE'
WHEN DELETING THEN 'DELETE'
END;
INSERT INTO TABLENAME_HISTO
(ACTIVITY_DATE, ACTION, MTC_USER,
old_field1, new_field1, old_field2, new_field2)
VALUES
(SYSDATE, strAction, USERID,
:OLD.field1, :NEW.field1, :OLD.field2, :NEW.field2)
Share and enjoy.
In SQL it is possible to run inserts and updates against a view, as long as the view only selects data from one table. However, deletes don't seem to work quite so well. Can anyone help out?
Take this view for example:
CREATE VIEW v_MyUpdatableView
AS
SELECT x.* FROM MyPrimaryTable x
LEFT OUTER JOIN AnotherTable y ON y.MyPrimaryTableId = x.Id
I can run updates and inserts against this view and they happily pass through to MyPrimaryTable.
However, if I run a delete I receive the following exception:
View or function 'v_MyUpdatableView' is not updatable because the modification affects multiple base tables.
Quote:
DELETE statements remove data in one or more of the member tables through the partitioned view. The DELETE statements must adhere to this rule:
DELETE statements are not allowed if there is a self-join with the same view, or any of the member tables.
Data Modification Rules - Creating a Partitioned View
I would just create a stored procedure that would delete the data from two tables. I know it's not pretty, but it would work or do logical deletes, where you update a column to be "deleted".