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
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>
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.
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 am using an oracle 11 table with interval partitioning and list subpartitioning like this (simplified):
CREATE TABLE LOG
(
ID NUMBER(15, 0) NOT NULL PRIMARY KEY
, MSG_TIME DATE NOT NULL
, MSG_NR VARCHAR2(16 BYTE)
) PARTITION BY RANGE (MSG_TIME) INTERVAL (NUMTOYMINTERVAL (1,'MONTH'))
SUBPARTITION BY LIST (MSG_NR)
SUBPARTITION TEMPLATE (
SUBPARTITION login VALUES ('FOO')
, SUBPARTITION others VALUES (DEFAULT)
)
(PARTITION oldvalues VALUES LESS THAN (TO_DATE('01-01-2010','DD-MM-YYYY')));
How do I drop a specific subpartitition for a specific month without knowing the (system generated) name of the subpartition? There is a syntax "alter table ... drop subpartition for (subpartition_key_value , ...)" but I don't see a way to specify the month for which I am deleting the subpartition. The partition administration guide does not give any examples, either. 8-}
You can use the metadata tables to get the specific subpartition name:
SQL> insert into log values (1, sysdate, 'FOO');
1 row(s) inserted.
SQL> SELECT p.partition_name, s.subpartition_name, p.high_value, s.high_value
2 FROM user_tab_partitions p
3 JOIN
4 user_tab_subpartitions s
5 ON s.table_name = p.table_name
6 AND s.partition_name = p.partition_name
7 AND p.table_name = 'LOG';
PARTITION_NAME SUBPARTITION_NAME HIGH_VALUE HIGH_VALUE
--------------- ------------------ ------------ ----------
OLDVALUES OLDVALUES_OTHERS 2010-01-01 DEFAULT
OLDVALUES OLDVALUES_LOGIN 2010-01-01 'FOO'
SYS_P469754 SYS_SUBP469753 2012-10-01 DEFAULT
SYS_P469754 SYS_SUBP469752 2012-10-01 'FOO'
SQL> alter table log drop subpartition SYS_SUBP469752;
Table altered.
If you want to drop a partition dynamically, it can be tricky to find it with the ALL_TAB_SUBPARTITIONS view because the HIGH_VALUE column may not be simple to query. In that case you could use DBMS_ROWID to find the subpartition object_id of a given row:
SQL> insert into log values (4, sysdate, 'FOO');
1 row(s) inserted.
SQL> DECLARE
2 l_rowid_in ROWID;
3 l_rowid_type NUMBER;
4 l_object_number NUMBER;
5 l_relative_fno NUMBER;
6 l_block_number NUMBER;
7 l_row_number NUMBER;
8 BEGIN
9 SELECT rowid INTO l_rowid_in FROM log WHERE id = 4;
10 dbms_rowid.rowid_info(rowid_in =>l_rowid_in ,
11 rowid_type =>l_rowid_type ,
12 object_number =>l_object_number,
13 relative_fno =>l_relative_fno ,
14 block_number =>l_block_number ,
15 row_number =>l_row_number );
16 dbms_output.put_line('object_number ='||l_object_number);
17 END;
18 /
object_number =15838049
SQL> select object_name, subobject_name, object_type
2 from all_objects where object_id = '15838049';
OBJECT_NAME SUBOBJECT_NAME OBJECT_TYPE
--------------- --------------- ------------------
LOG SYS_SUBP469757 TABLE SUBPARTITION
As it turns out, the "subpartition for" syntax does indeed work, though that seems to be a secret Oracle does not want to tell you about. :-)
ALTER TABLE TB_LOG_MESSAGE DROP SUBPARTITION FOR
(TO_DATE('01.02.2010','DD.MM.YYYY'), 'FOO')
This deletes the subpartition that would contain MSG_TIME 2010/02/01 and MSG_NR FOO. (It is not necessary that there is an actual row with this exact MSG_TIME and MSG_NR. It throws an error if there is no such subpartition, though.)
Thanks for the post - it was very useful for me.
One observation though on the above script to identify the partition and delete it:
The object_id returned by dbms_rowid.rowid_info is not the object_id of the all_objects table. It is actually the data_object_id. It is observed that usually these ids match. However, after truncating the partitioned table several times, these ids diverged in my database. Hence it might be reasonable to instead use the data_object_id to find out the name of the partition:
select object_name, subobject_name, object_type
from all_objects where data_object_id = '15838049';
From the table description of ALL_OBJECTS:
OBJECT_ID Object number of the object
DATA_OBJECT_ID Object number of the segment which contains the object
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_rowid.htm
In the sample code provided in the above link, DBMS_ROWID.ROWID_OBJECT(row_id) is used instead to derive the same information that is given by dbms_rowid.rowid_info. However, the documentation around this sample mentions that it is a data object number from the ROWID.
Examples
This example returns the ROWID for a row in the EMP table, extracts
the data object number from the ROWID, using the ROWID_OBJECT function
in the DBMS_ROWID package, then displays the object number:
DECLARE object_no INTEGER; row_id ROWID; ... BEGIN
SELECT ROWID INTO row_id FROM emp
WHERE empno = 7499; object_no := DBMS_ROWID.ROWID_OBJECT(row_id); DBMS_OUTPUT.PUT_LINE('The obj. # is
'|| object_no); ...