How do I invalidate a table in Oracle 11g on purpose? - sql

I'm writing a small query to find invalid tables in Oracle :
select * from user_tables where status != 'VALID'
For testing, I thought it would be good to create a table and invalidate it on purpose. Is there a way to do this?
Invalidating a view is easy, just drop one of the underlying tables.
Any hint welcome.

You won't see status INVALID in user_tables, however, you would see that in [USER|ALL|DBA]_OBJECTS view.
One simple way is to create the table using an object type, and force the object type attribute to invalidate.
For example,
SQL> CREATE OR REPLACE TYPE mytype AS OBJECT(col1 VARCHAR2(10))
2 /
Type created.
SQL>
SQL> CREATE TABLE t(col1 NUMBER,col2 mytype)
2 /
Table created.
SQL>
SQL> SELECT object_name, object_type, status FROM user_objects WHERE object_name='T'
2 /
OBJECT_NAME OBJECT_TYPE STATUS
----------- ----------------------- -----------
T TABLE VALID
SQL>
So, the table is now in VALID status. Let's make it INVALID:
SQL> ALTER TYPE mytype ADD ATTRIBUTE col2 NUMBER INVALIDATE
2 /
Type altered.
SQL>
SQL> SELECT object_name, object_type, status FROM user_objects WHERE object_name='T'
2 /
OBJECT_NAME OBJECT_TYPE STATUS
----------- ----------------------- -----------
T TABLE INVALID
SQL>

Its an old question but I want to point on something for future readers, the opposit of valid in the status user_tables is UNUSABLE so if you want to make a table UNUSABLE,A DROP TABLE operation failed from oracle doc
If a previous DROP TABLE operation failed, indicates whether the table
is unusable (UNUSABLE) or valid (VALID)
As for the type INVALID in user_objects its mainly related to views/package/procedure however lalit kumar gave a good example where a table is invalid.

Related

How to set the right to see a view in oracle?

I am logged in as user "a" in my oracle database.
I can write a query like "Select * from MyView" and I get all results - thats fine.
BUT I can't see the view itself in SqlDeveloper in my View-tree (list), additional to that I am not the owner (which I can see with "Select * from all_views").
How can I change the rights of this view to see "MyVIew" in the tree?
#Littlefoot is correct in his answer. You could of course also browse to the view directly via the 'Other Users' portion of the tree, then drill down into the Views.
BUT, you could also just set your Views filter to 'Include Synonyms'
I wrote a story on this topic for TABLES, but it also applies to VIEWS here.
I presume you should query all_objects to see what you're actually dealing with. Why? Because of the following example:
Connected as user mike, I'll create a table, grant select on it to public and create a public synonym:
SQL> connect mike/lion
Connected.
SQL> create table test as select 'Littlefoot' name from dual;
Table created.
SQL> create public synonym myview for test;
Synonym created.
SQL> grant select on test to public;
Grant succeeded.
Connect as another user, scott and select from myview:
SQL> connect scott/tiger
Connected.
SQL> select * from myview;
NAME
----------
Littlefoot
Right; it works. Where is it in SQL Developer?
Aha, it is in public synonyms (I applied filter on name, looking for MYVIEW to skip zillion other public synonyms).
Or, in SQL*Plus:
SQL> select object_name, object_type, owner from all_objects where object_name = 'MYVIEW';
OBJECT_NAME OBJECT_TYPE OWNER
------------------------------ ------------------- ------------------------------
MYVIEW SYNONYM PUBLIC
SQL>
Therefore, I suggest you do the same - query all_objects and you'll know something more about the issue.
you can not change the right of the view to see it your View-tree (list), because it is not your own object. To have the view in your View-tree (list) you have to create it in your own shema.

Oracle SQL Developer flag my working views as broken

Can anyone share me some light on why my Oracle SQL Developer flagged my view as broken while it is actually working?
It is not just 1 view, but 10 views have the same problem, they are all created in a different time, with subquery or joining to multiple tables and is always working fine.
Thanks in advance!
Probably the view was invalidated by a change to a referenced object. Like stored PL/SQL, a recompilation will occur when it is next used, when it will become valid again. For example:
SQL> create table demo (id integer);
Table created
SQL> create or replace view v1 as select id from demo;
View created
SQL> select o.status from user_objects o where object_type = 'VIEW' and object_name = 'V1';
STATUS
-------
VALID
SQL> alter table demo modify id varchar2(10);
Table altered
SQL> select o.status from user_objects o where object_type = 'VIEW' and object_name = 'V1';
STATUS
-------
INVALID
SQL> select * from v1;
ID
----------
SQL> select o.status from user_objects o where object_type = 'VIEW' and object_name = 'V1';
STATUS
-------
VALID

How to get user/creation date of Trigger in Oracle

Is there any way to get the creation date(time) of the trigger ?
I tried the following query:
select CREATED from user_objects where object_name = '&MY_TRIGGER_NAME'
but i think, i get the last modification/run date, not the creation time.
And also, i want to get the user who created the trigger...if it is possible.
As per the oracle documentation, fields of the USER_OBJECTS is described as:
CREATED: Timestamp for the creation of the object
LAST_DDL_TIME: Timestamp for the last modification of the object resulting from a DDL statement (including grants and revokes)
Let's do one exercise:
Checking in the USER_OBJECTS table for trigger TRG_T
SQL> SELECT OBJECT_NAME,
2 OBJECT_TYPE,
3 CREATED,
4 LAST_DDL_TIME
5 FROM USER_OBJECTS
6 WHERE OBJECT_NAME = 'TRG_T';
no rows selected
Now, Let's create the trigger TRG_T
SQL> CREATE OR REPLACE TRIGGER TRG_T BEFORE
2 INSERT ON T
3 FOR EACH ROW
4 BEGIN
5 NULL;
6 END;
7 /
Trigger created.
Let's check in the USER_OBJECTS
SQL> SELECT OBJECT_NAME,
2 OBJECT_TYPE,
3 CREATED,
4 LAST_DDL_TIME
5 FROM USER_OBJECTS
6 WHERE OBJECT_NAME = 'TRG_T';
OBJECT_NAME OBJECT_TYPE CREATED LAST_DDL_TIME
--------------- --------------- -------------------- --------------------
TRG_T TRIGGER 02-jul-2020 12:41:29 02-jul-2020 12:41:29
Currently, CREATED and LAST_DDL_TIME are the same because the last DDL operation on the trigger is when we created it.
Let's modify the trigger:
SQL> CREATE OR REPLACE TRIGGER TRG_T BEFORE
2 INSERT ON T
3 FOR EACH ROW
4 BEGIN
5 NULL; -- do some changes
6 NULL; -- CHANGED THIS
7 END;
8 /
Trigger created.
Now, let's again check in the USER_OBJECTS:
SQL> SELECT OBJECT_NAME,
2 OBJECT_TYPE,
3 CREATED,
4 LAST_DDL_TIME
5 FROM USER_OBJECTS
6 WHERE OBJECT_NAME = 'TRG_T';
OBJECT_NAME OBJECT_TYPE CREATED LAST_DDL_TIME
--------------- --------------- -------------------- --------------------
TRG_T TRIGGER 02-jul-2020 12:41:29 02-jul-2020 12:42:05
See the CREATED and LAST_DDL_TIME is different here
CREATED is the
timestamp for the creation of the object
in USER_OBJECTS/ALL_OBJECTS/DBA_OBJECTS and not the last modified date which isLAST_DDL_TIME.
To get trigger owner, you need to use OWNER column in ALL_TRIGGERS/DBA_TRIGGERS because USER_TRIGGERS displays only your own triggers without any OWNER column.
there is a field called "created" in user_objects view which tells the creation time of the object. There is another column called last_ddl_time which would show the time of the last creation of the DDL
As for the user who created the object i am not sure its tracked unless you have got a logon trigger that logs this information i believe

Change table name with sysdate

I want to change a table name by appending SYSDATE to it. For example, I want to change table EXAMPLE_TABLE to EXAMPLE_TABLE_05_01_2015, but I want to get the date from SYSDATE.
I prepared the following but it is not working:
ALTER TABLE "MYDB"."EXAMPLE_TABLE" rename to (SELECT 'EXAMPLE_TABLE' || TO_CHAR(SYSDATE, '_dd_MM_yyyy') FROM DUAL);
How can I make it work?
Here is the error:
SQL Error: ORA-14047: ALTER TABLE|INDEX RENAME may not be combined with other operations
14047. 00000 - "ALTER TABLE|INDEX RENAME may not be combined with other operations"
*Cause: ALTER TABLE or ALTER INDEX statement attempted to combine
a RENAME operation with some other operation which is illegal
*Action: Ensure that RENAME operation is the sole operation specified in
ALTER TABLE or ALTER INDEX statement;
Use execute immediate.
begin
execute immediate
'alter table mydb.example_table rename to ' ||
'example_table_' || to_char(sysdate, 'dd_mm_yyyy');
end;
/
That said, I have the hunch that you'd be better off using partitioned tables.
In SQL*Plus, you could use the variable substitution.
Just another way :
SQL> CREATE TABLE t(ID NUMBER)
2 /
Table created.
SQL>
SQL> COLUMN new_tablename NEW_VALUE new_tablename
SQL> SELECT 't_' || to_char(sysdate, 'dd_mm_yyyy') AS new_tablename from dual
2 /
NEW_TABLENAM
------------
t_05_01_2015
SQL>
SQL> RENAME t TO &new_tablename
2 /
old 1: RENAME t TO &new_tablename
new 1: RENAME t TO t_05_01_2015
Table renamed.
SQL>
SQL> select * from t_05_01_2015;
no rows selected
SQL>
So, now the table T is renamed to T_05_01_2015.

Oracle 11gR2 Function based index error

I want to create a simple function based index on a simple table but i get error.
So, first of all I created a function
CREATE OR REPLACE FUNCTION promo_function(p_promo_category VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
RETURN UPPER(p_promo_category);
END promo_function;
Then I would execute this, but fails
CREATE INDEX promotions_fbi
ON SH.PROMOTIONS (promo_function (promo_category));
Why? The error is ORA-00904:"PROMO_FUNCTION": Invalid identifier
But the function works well in a query:
SELECT *
FROM sh.sales s,
sh.promotions p,
sh.times t
WHERE s.promo_id = p.promo_id
AND s.time_id = t.time_id
AND t.time_id BETWEEN DATE '2000-01-01' AND DATE '2000-03-31'
AND promo_function(p.promo_category) = 'AD NEWS';
Many thanks!
There is nothing inherently wrong with your code. I can create a function-based index like this:
SQL> create table promotions (promo_category varchar2(10))
2 /
Table created.
SQL> CREATE OR REPLACE FUNCTION promo_function
2 (p_promo_category in VARCHAR2)
3 RETURN VARCHAR2 DETERMINISTIC
4 IS
5 BEGIN
6 RETURN UPPER(p_promo_category);
7 END promo_function;
8 /
Function created.
SQL> CREATE INDEX promotions_fbi
2 ON PROMOTIONS (promo_function (promo_category));
Index created.
SQL>
The only difference between my code and yours is that I don't prefix the table in the CREATE INDEX statement. Everything is in the same schema, so I don't need to.
So, can I re-create your scenario? Here's one way. I drop the index and function, then give another uses all privileges on teh table...
SQL> drop index promotions_fbi;
Index dropped.
SQL> drop function PROMO_FUNCTION;
Function dropped.
SQL> grant all on promotions to B;
Grant succeeded.
SQL>
As that user I can create a normal index ...
SQL> conn b/b
Connected.
SQL> select * from apc.promotions;
no rows selected
SQL> CREATE INDEX promotions_i
2 ON APC.PROMOTIONS (promo_category);
Index created.
SQL>
However, if I create a function I cannot create a function-based index using it....
SQL> conn b/b
Connected.
SQL> CREATE INDEX promotions_fbi
2 ON APC.PROMOTIONS (promo_function (promo_category));
ON APC.PROMOTIONS (promo_function (promo_category))
*
ERROR at line 2:
ORA-00904: : invalid identifier
SQL>
The invalid identifier fingers the function name. Why? Because although schema B would own the index schema APC owns the table, and needs to be able to execute the function too.
The solution is to grant execute rights on the function to the table owner:
SQL> conn b/b
Connected.
SQL> grant execute on promo_function to APC;
Grant succeeded.
SQL> CREATE INDEX promotions_fbi
2 ON APC.PROMOTIONS (B.promo_function (promo_category));
Index created.
SQL>
Note that we must explicitly reference the function owner as well as the table owner in this statement. It's a bit nasty, and that's why it's generally a bad idea to spread privileges across two schemas in this fashion.
Not sure how #zaratustra gets their findings, as I can definitely create function-based in indexes using the word FUNCTION in the name...
SQL> r
1 select i.table_owner, i.owner as index_owner, i.index_name
2 , i.index_type, e.column_expression
3 from all_indexes i
4 left join all_ind_expressions e
5 on i.owner = e.index_owner
6 and i.index_name = e.index_name
7* where i.table_name = 'PROMOTIONS'
TABLE_OWNER INDEX_OWNER
------------------------------ ------------------------------
INDEX_NAME INDEX_TYPE
------------------------------ ---------------------------
COLUMN_EXPRESSION
--------------------------------------------------------------------------------
APC APC
PROMOTIONS_FBI FUNCTION-BASED NORMAL
"APC"."PROMO_FUNCTION"("PROMO_CATEGORY")
APC A
PROMO_B_I FUNCTION-BASED NORMAL
"A"."B_FUNCTION"("PROMO_CATEGORY")
APC APC
PROMOTIONS_I NORMAL
SQL>
Although I am on a different point release so that might explain it
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production
SQL>
During my experiments I realized that Oracle can't let you create function-based index with the function word in the name of the procedure. Looks like a bug for me:
CREATE OR REPLACE FUNCTION func_function(p_promo_category IN VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
RETURN UPPER(p_promo_category);
END func_function;
create table t1 (
promo_category varchar2(4000)
);
Table created
CREATE INDEX promotions_fbi ON t1 (func_function (promo_category));
ORA-00911: invalid character
Let's create a function without the function word in the name:
CREATE OR REPLACE FUNCTION func_functio(p_promo_category IN VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
RETURN UPPER(p_promo_category);
END func_functio;
CREATE INDEX promotions_fbi ON t1 (func_functio (promo_category));
Index created
select index_name, index_type
from user_indexes
where lower(index_name) = 'promotions_fbi'
INDEX_NAME INDEX_TYPE
-------------------------------------
PROMOTIONS_FBI FUNCTION-BASED NORMAL
My Oracle version:
select banner from v$version
BANNER
----------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production