For some reason, I should keep the Mview which has the same name as a base table.
Can you let me know how to issue DML on a base table in this case?
As you can see in the below example, I wanted to issue DML for the base table, however, Mview is considered at the first.
DROP TABLE SRC_TABLE PURGE;
DROP TABLE TGT_TABLE PURGE;
DROP MATERIALIZED VIEW TGT_TABLE;
DROP MATERIALIZED VIEW LOG ON SRC_TABLE ;
CREATE TABLE SRC_TABLE(X NUMBER(8) PRIMARY KEY);
CREATE TABLE TGT_TABLE(X NUMBER(8) PRIMARY KEY);
INSERT INTO SRC_TABLE VALUES(55);
COMMIT;
CREATE MATERIALIZED VIEW LOG ON SRC_TABLE WITH PRIMARY KEY, ROWID;
CREATE MATERIALIZED VIEW TGT_TABLE
ON PREBUILT TABLE WITH REDUCED PRECISION
USING INDEX
REFRESH FAST ON DEMAND
WITH PRIMARY KEY USING DEFAULT LOCAL ROLLBACK SEGMENT
USING ENFORCED CONSTRAINTS DISABLE ON QUERY COMPUTATION DISABLE QUERY REWRITE
AS
SELECT * FROM SRC_TABLE
/
INSERT INTO SRC_TABLE VALUES (10);
INSERT INTO SRC_TABLE VALUES (20);
COMMIT;
EXEC DBMS_MVIEW.REFRESH('TGT_TABLE');
SELECT * FROM SRC_TABLE;
SELECT * FROM TGT_TABLE;
SQL> DELETE FROM TGT_TABLE;
DELETE FROM TGT_TABLE
*
ERROR at line 1:
ORA-01732: data manipulation operation not legal on this view
TGT_TABLE is a physical table which is used by the materialized view as a "storage"
SRC_TABLE is a table which is used as the "source" of data for that materialized view
you
can't modify the materialized view or the underlying table which is used as its storage
can modify table which is used as the source, and that would be the SRC_TABLE, not TGT_TABLE
It is kind of confusing because it looks like you have two objects having the same name, which is impossible. For example:
SQL> select object_name, object_type from user_objects where object_name = 'DEPT';
OBJECT_NAME OBJECT_TYPE
--------------- -------------------
DEPT TABLE
SQL> create materialized view dept as select * From dept;
create materialized view dept as select * From dept
*
ERROR at line 1:
ORA-00955: name is already used by an existing object
SQL>
However, you chose to re-use existing table (TGT_TABLE; it is the ON PREBUILT TABLE clause) so it looks as if there were two objects with the same name. That's how materialized view is designed - has "query" (a "view" which is used to refresh data), and "physical storage" (a "table") which actually contains data.
If you didn't use table that already exists and created a materialized view on some table, you'd still see two objects with the same name. For example:
SQL> select object_name, object_type from user_objects where object_name = 'TEST';
no rows selected
SQL> create materialized view test as select * from dept;
Materialized view created.
SQL> select object_name, object_type from user_objects where object_name = 'TEST';
OBJECT_NAME OBJECT_TYPE
--------------- -------------------
TEST TABLE
TEST MATERIALIZED VIEW
See? Something what is impossible to achieve otherwise.
What you did was trying to modify the storage table, and it didn't work:
SQL> update test set loc = 'Zagreb' where deptno = 10;
update test set loc = 'Zagreb' where deptno = 10
*
ERROR at line 1:
ORA-01732: data manipulation operation not legal on this view
But, you can / should modify the table materialized view is created against:
SQL> update dept set loc = 'Zagreb' where deptno = 10;
1 row updated.
SQL>
Anyway, modifying the storage table doesn't make much sense as those changes would be overwritten at the next materialized view refresh.
So, in your case, you should update/delete SRC_TABLE, not TRG_TABLE.
Related
Is there a Oracle data dictionary table that associates a trigger with its trigger audit table?
enter image description here
You can check out DBA_DEPENDENCIES
SELECT *
FROM dba_dependencies
WHERE TYPE = 'TRIGGER' AND referenced_type = 'TABLE';
Query user_dependencies.
For example:
SQL> create or replace trigger trg_test
2 before insert on emp
3 for each row
4 begin
5 insert into dept (deptno) values (:new.deptno);
6 insert into owner (id_owner, name) values (:new.empno, :new.ename);
7 end;
8 /
Trigger created.
SQL> select referenced_name, referenced_type
2 from user_dependencies
3 where referenced_owner = user
4 and name = 'TRG_TEST';
REFERENCED_NAME REFERENCED_TYPE
-------------------- ------------------
DEPT TABLE --> trigger line #5
EMP TABLE --> trigger line #2
OWNER TABLE --> trigger line #6
SQL>
Bonus: there's that nice view called dictionary. If you query it, it reveals useful information and shows which tables (views) you could try to query to find information you need. In this very case:
SQL> select table_name, comments
2 from dictionary
3 where lower(comments) like '%dependenc%';
TABLE_NAME COMMENTS
------------------------------ ------------------------------------------------------------
ALL_DEPENDENCIES Dependencies to and from objects accessible to the user
ALL_XSC_SECURITY_CLASS_DEP All security class dependencies in the database
USER_DEPENDENCIES Dependencies to and from a users objects
SQL>
I have about 50 tables and I would like to know if there is any way to obtain with a query, which columns of my tables are created in a specific tablespace? can you know? or know what things are created in that tablespace?
I guess this might be what you're looking for.
Create a sample table which contains a CLOB datatype column:
SQL> create table test1
2 (id number,
3 text clob
4 );
Table created.
LOB columns can be stored into a different tablespace than the rest of columns; although I didn't specify storage info (so TEXT column resides in the same tablespace as the rest of the columns), querying USER_LOBS returns info you're interested in:
SQL> select column_name,
2 table_name,
3 tablespace_name --> this column
4 from user_lobs
5 where table_name = 'TEST1';
COLUMN_NAM TABLE_NAME TABLESPACE_NAME
---------- ---------- ------------------------------
TEXT TEST1 USERS
SQL>
Another free hint: when you're unsure of where to look for certain things, try to ask the Dictionary. For example:
SQL> select * From dictionary where lower(table_name) like '%lob%';
TABLE_NAME COMMENTS
------------------------------ --------------------------------------------------
ALL_LOBS Description of LOBs contained in tables accessible
to the user
ALL_LOB_PARTITIONS
<snip>
USER_LOBS Description of the user's own LOBs contained in the
user's own tables
<snip>
15 rows selected.
SQL>
It looks like we have two objects in our database that have the same name, 'X'. One is a Materialized View and the other is a table. I believe that the MV came first and then the developers switched over to using traditional table type object. In our db, I see that the definition of the MV matches the columns of the table.
When I perform the following query
select * from all_tab_columns c where c.TABLE_NAME = 'X' order by C.COLUMN_ID;
I get a SINGLE list of columns. I assume that I am getting the list of all of the columns in the table, not the materialized view, which could contain different columns than the table of the same name but in my case, as already mentioned, the columns in each happen to match.
I guess that I expected that both sets of columns, a set for the MV and a set of columns for the table, would be returned from the ALL_TAB_COLUMNS view and that they would be separated by a field that stored the TYPE of the parent, for example PARENT_OBJECT_TYPE = 'MATERIALIZED VIEW' or PARENT_OBJECT_TYPE = 'TABLE' and that this would be part of the key to the ALL_OBJECTS table (OWNER, OBJECT_NAME, OBJECT_TYPE) but this is not the case.
How do I get the list of columns in a Materialized VIEW? Or is my assumption wrong that it is not possible to have two different sets columns for two objects with the same name, one being an MV and the other being a TABLE? I am unable to create objects in the database to test the latter case.
You got those columns already. This is how Oracle sets it up.
Here's an example:
There's no object named LF in my schema:
SQL> select object_name, object_type from user_objects where object_name = 'LF';
no rows selected
I'll create a materialized view:
SQL> create materialized view lf as select * From dept;
Materialized view created.
What do I have?
SQL> select object_name, object_type from user_objects where object_name = 'LF';
OBJECT_NAME OBJECT_TYPE
------------------------------ -------------------
LF TABLE
LF MATERIALIZED VIEW
SQL>
See? A table, and a materialized view. Why? Because Oracle uses
table to actually store data (as materialized views do have data, unlike "ordinary" views which are just stored queries)
materialized view, which contains info about refreshing options
So, when you queried all_tab_columns, you did get what you asked for:
SQL> select column_name, data_type from user_tab_columns where table_name = 'LF';
COLUMN_NAME DATA_TYPE
------------------------------ --------------------
DEPTNO NUMBER
DNAME VARCHAR2
LOC VARCHAR2
SQL>
A little bit about prebuilt table:
Dropping the old MV first:
SQL> drop materialized view lf;
Materialized view dropped.
Create a table which will be used as a "target" of the materialized view's query; it'll hold data:
SQL> create table lf as select * From dept where 1 = 2;
Table created.
SQL> select * From lf;
no rows selected
Use on prebuilt table option:
SQL> create materialized view lf on prebuilt table
2 as select * From dept;
Materialized view created.
SQL> select * From lf;
no rows selected
Empty; refresh it (on demand, right?):
SQL> exec dbms_mview.refresh('LF');
PL/SQL procedure successfully completed.
SQL> select * From lf;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL>
I created 1 object.
create type tab_billing as object(invoice_no number,
customername varchar2(100)
);
Now i created a table with the object as a column.
CREATE TABLE tab1 (col1 number,COL2 tab_billing);
Is there anyway I can ONLY select invoice_no from the tab1.
select col2 from tab1;
Is givng me both invoice_no and customername. Substr function is not working here.
You can query the column value's object field directly, but to avoid confusing the object name resolution steps you have to supply and use a table alias:
select t1.col2.invoice_no from tab1 t1;
This is mentioned in the documentation:
To avoid inner capture and similar problems resolving references, Oracle Database requires you to use a table alias to qualify any dot-notational reference to subprograms or attributes of objects.
Qualifying the column with the the table name isn't enough; using select tab1.col2.invoice_no from tab1 gets ORA-00904. You have to use a table alias - although, slightly bizarrely, it still works if the alias is the same as the table name, so select tab1.col2.invoice_no from tab1 tab1 (i.e. aliasing tab1 as tab1, which is normally redundant) works too.
Quick demo:
create type tab_billing as object(invoice_no number,
customername varchar2(100)
);
/
Type TAB_BILLING compiled
CREATE TABLE tab1 (col1 number,COL2 tab_billing);
Table TAB1 created.
insert into tab1 values (1, tab_billing(42, 'Test'));
1 row inserted.
select t1.col2.invoice_no from tab1 t1;
COL2.INVOICE_NO
---------------------------------------
42
You can use TREAT:
SQL> create type tab_billing as object(invoice_no number,
2 customername varchar2(100)
3 );
4 /
Type created.
SQL> CREATE TABLE tab1 (col1 number,COL2 tab_billing);
Table created.
SQL> insert into tab1 values (1, tab_billing(10, 'ten')) ;
1 row created.
SQL> select col1,
2 TREAT(col2 AS tab_billing).invoice_no as invoice_no,
3 TREAT(col2 AS tab_billing).customername as customername
4 from tab1;
COL1 INVOICE_NO CUSTOMERNAME
------ ---------- --------------------
1 10 ten
Oracle Version: 11.2.0.1.0. I imported a schema from database dump. I am connecting as HR.
I am able to see a table via 'desc table_name'. When I query DBA_* objects, the output is ok.
But when doing insert, I get ORA-00942.
SQL> desc EMPLOYEE
Name Null? Type
--------------------------------------- -------- ----------------------------
EMPLOYEE_ID NOT NULL NUMBER(16)
EMPLOYEE_NAME NOT NULL VARCHAR2(200 CHAR)
SQL> select count(*) from dba_tables where owner = 'HR'
2 and table_name = 'EMPLOYEE'
3 /
COUNT(*)
----------
1
SQL> select object_type, object_name, created from dba_objects where owner = 'HR' and object_name = 'EMPLOYEE'
OBJECT_TYPE OBJECT_NAME CREATED
TABLE EMPLOYEE 03-APR-15
SQL> insert into EMPLOYEE ( EMPLOYEE_ID, EMPLOYEE_NAME ) values ( 11,'x')
2 /
insert into EMPLOYEE ( EMPLOYEE_ID, EMPLOYEE_NAME ) values ( 11,'x')
*
ERROR at line 1:
ORA-00942: table or view does not exist
This looks like bug 9577583, which affects 11.2.0.1, as well as some earlier versions. If you have access to My Oracle Support, look at document ID 9577583.8.
The very high level synopsis, since I can't reproduce what that says in any detail, is that this can occur when identical objects appear in multiple schemas - you have the same employee table in the hr and scott schemas, for example - and Oracle gets confused about which object it's supposed to be looking at.
It's possible that flushing the shared pool and/or forcing a hard parse might resolve the issue, at least temporarily, but I don't have a base version to test that on; and you'd be better off patching if you're able to. You might want to raise a service request with Oracle first to verify that this is what you are seeing.
what user are you running the insert as? unless you are connected as the "hr" user your code will need to look like this...
insert into HR.EMPLOYEE ( EMPLOYEE_ID, EMPLOYEE_NAME ) values ( 11,'x')
you need to include the schema name in the insert
The table was base table for a MV ( materialized view ). Due to a bug if the MV LOG is dropped using any method other than 'drop mv log' command, any subsequent DML will raise this error. The resolution is to use 'drop mv log' on such table. See Doc ID 1912363.1