I have created a sequence plsql_profile_runnumber in sys user, but I cannot find it in dba_objects or dba_sequences. Please find the executiion details:
SQL> create sequence plsql_profiler_runnumber start with 1 nocache;
Sequence created.
SQL> select * from sys.dba_objects where object_name ='PLSQL_PROFILE_RUNNUMBER';
no rows selected
SQL> grant select on plsql_profile_runnumber to vps_user;
grant select on plsql_profile_runnumber to vps_user
*
ERROR at line 1:
ORA-00942: table or view does not exist
create sequence plsql_profiler_runnumber start with 1 nocache;
select * from sys.dba_objects where object_name ='PLSQL_PROFILE_RUNNUMBER';
Answer: The sequence you created was PLSQL_PROFILER_RUNNUMBER.
The object name you reference was PLSQL_PROFILE_RUNNUMBER.
The two names are different. PROFILER vs. PROFILE.
PLSQL_PROFILE_RUNNUMBER
and
plsql_profiler_runnumber
are different by
ending r of profiler.
Related
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
I use the query CTAS to create a new table, however, when CTAS has finished, other users canĀ“t select the new table, but they had access to the old, Is it a way to pass all the users and groups to the new table? because the old table will be deleted.
"A way" is to grant (at least) select privileges to all those users.
If you used a role and granted select privilege to that role, and then granted role to those users, things would be quite simpler - just grant select privilege on the new table to the same role, and everyone will "see" it.
Otherwise, you can write query to create those grant statements for you.
For example, in Scott's schema there's the EMP table. I've previously granted privileges on it to other users in my database, and now I'm going to create a "new" CTAS table and grant privileges to the same set of users.
SQL> create table my_new_table as select * from emp;
Table created.
SQL> select 'grant select on my_new_table to ' || grantee ||';' run_me
2 from all_tab_privs_made
3 where owner = 'SCOTT'
4 and table_name = 'EMP';
RUN_ME
---------------------------------------------------------------
grant select on my_new_table to SYS;
grant select on my_new_table to SUPERUSER;
grant select on my_new_table to MY_ROLE;
grant select on my_new_table to MIKE;
Now simply copy/paste the above bunch of grant statements:
SQL> grant select on my_new_table to SYS;
Grant succeeded.
SQL> grant select on my_new_table to SUPERUSER;
Grant succeeded.
SQL> grant select on my_new_table to MY_ROLE;
Grant succeeded.
SQL> grant select on my_new_table to MIKE;
Grant succeeded.
SQL>
If there's zillion of users, PL/SQL option would be simpler as it would do everything for you (i.e. no copy/pasting):
SQL> begin
2 for cur_r in (select grantee
3 from all_tab_privs_made
4 where owner = 'SCOTT'
5 and table_name = 'EMP'
6 )
7 loop
8 execute immediate 'grant select on my_new_table to ' || cur_r.grantee;
9 end loop;
10 end;
11 /
PL/SQL procedure successfully completed.
SQL>
If you create a table using CTAS from an existing one, the new one is a new segment, therefore it lacks of privileges. You need to recover the permissions granted to the old table and granting to the new one. For that you can use several alternatives ( dbms_metadata, dynamic sql ).
For the purposes , I'd do it like this
SQL> CREATE TABLE T2 AS SELECT * FROM T1 ;
SQL> begin
dbms_metadata.set_transform_param (dbms_metadata.session_transform,
'SQLTERMINATOR', true);
dbms_metadata.set_transform_param (dbms_metadata.session_transform, 'PRETTY',
true);
end;
/
select replace(dbms_metadata.get_dependent_ddl('OBJECT_GRANT', 'T1', 'OWNER_OF_T1' ),'T1','T2') AS ddl
from dual;
The first part is for creating in a nice format the list of necessary grants. The second part retrieves all the privileges granted to T1 and generates the list of grants statements for running to the T2 table. Then you only need to run the list of grants
As I said, there are several alternatives to do this.
Regards
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.
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
Recently , I am facing an issue with sequence in Oracle.
alter sequence seq_name increment by 100
will give me an error "Invalid sequence name"
However, if I changed it to
alter sequence "seq_name" increment by 100
It will work perfectly fine. Anyone is able to explain the rational behind this?
Thanks
Sebastian
ps. I am using rails with oci8 to create my oracle tables.
Your sequence was created with case-sensitive name (using quatation marks), so you can refer to it only with strict name - in quotation marks. If you want to refer to it without such problems just create sequence not using quotation marks. Examples below (with table name):
SQL> create table "t1"(c int);
Table created.
SQL> select * from t1;
select * from t1
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select * from "t1";
no rows selected
SQL> select * from "T1";
select * from "T1"
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> create table t2(c int);
Table created.
SQL> select * from t2;
no rows selected
SQL> select * from T2;
no rows selected
SQL> select * from "t2";
select * from "t2"
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select * from "T2"; -- name without quatation marks is uppercase by default
no rows selected
Sequence was created as lowercase. Like this:
CREATE SEQUENCE "seq_name" MINVALUE 1 MAXVALUE 999999999999999 INCREMENT BY 2 START WITH 1 CACHE 20 NOCYCLE NOKEEP NOSCALE GLOBAL ;
Example:
select * from user_sequences where sequence_name='SEQ_NAME'; --No rows selected
select * from user_sequences where sequence_name='seq_name'; -- 1 row
If you create with name : "SEQ_name".
select * from user_sequences where sequence_name='SEQ_name'; -- 1 row
Because,
when you create an object (with object name enclosed with double quotes) it will store/create as it is. Without double quotes, it would be uppercase.