Check if a view was created with the FORCE option - oracle

How can I check in Oracle if a view was created with the FORCE option?
In the view sys.all_views there is no column for this option and the query text itself doesn't contain the CREATE part.

I can confirm what #a_horse_with_no_name suggested: FORCE isn't stored in the data dictionary, and dbms_metadata.get_ddl makes it up, as probably TOAD does, too:
CREATE TABLE t (i NUMBER);
CREATE FORCE VIEW f AS SELECT * FROM t;
CREATE NOFORCE VIEW n AS SELECT * FROM t;
USER_VIEWS, USER_OBJECTS, SYS.VIEW$ and SYS.OBJ$ are identical for the two views. And dbms_metadata.get_ddl adds FORCE in any case:
SELECT dbms_metadata.get_ddl('VIEW', view_name) FROM user_views;
CREATE OR REPLACE FORCE EDITIONABLE VIEW "SO"."F" ("I") AS
SELECT "I" FROM t"
CREATE OR REPLACE FORCE EDITIONABLE VIEW "SO"."N" ("I") AS
SELECT "I" FROM t"

Related

Oracle - using synonym as variable

i need to use synonym as variable in a block. I have 2 different schemas with same tables on them and job that switches between schemas making one active. Now I want to write a block checking which schema is active with ALL_SYNONYMS and using result as part of a query.
Here is example:
DECLARE
OWNER VARCHAR2(15);
BEGIN
SELECT TABLE_OWNER
INTO OWNER
FROM ALL_SYNONYMS
WHERE TABLE_NAME = 'MY_TABLE1';
SELECT *
FROM OWNER.MY_TABLE2 ;
END;
But I’m getting ORA-06550 table or view does not exist, and when i run query itself where i put value from ALL_SYNONYMS it returns result.
Any idea how to fix this?
Thanks
You are attempting using symptoms incorrectly. Synonyms are used so you do not need to know which is active. According to the documentation:
Synonyms provide both data independence and location transparency.
Synonyms permit applications to function without modification
regardless of which user owns the table or view and regardless of
which database holds the table or view.
You just use the synonym instead of the object itself.
create table evens( id integer generated always as identity
, val integer
) ;
create table odds( id integer generated always as identity
, val integer
) ;
insert all
when mod(val,2) = 0 then into evens(val)
when mod(val,2) = 1 then into odds(val)
select level val
from dual connect by level <= 10;
-- create the synonym then use it in Select;
create or replace synonym current_even_odd for evens;
select * from current_even_odd;
-- now change the synonym, then run the EXACT same query.
create or replace synonym current_even_odd for odds;
select * from current_even_odd;
In this case it is not quite without modification, you need to change the synonym, But it seems you are trying that already.
Note: You cannot create a synonym for a schema but must point it to a specific object.
I attempted a db<>fiddle for the above, but it appears it is having problems at the moment.
I agree with Belayer that the synonym should provide a layer of abstraction on your tables and your procedure shouldn't need to know what the schema is. But the "table or view does not exist" error is likely an issue related to privileges and definer's rights versus invoker's rights.
To directly reference an object in a procedure, the procedure's schema must have a direct grant to the table. However, an ad hoc query only needs a role with privileges on the object. This is why the SQL will work in your IDE but not in the procedure. Ensure the code that modifies objects and switches synonyms is granting privileges to both roles and directly to schemas.
If direct grants are not possible, you will need to modify the procedure to use AUTHID CURRENT_USER and change the SQL statements to use dynamic SQL - which can be a huge pain. For example:
create or replace procedure test_procedure authid current_user is
v_count number;
begin
execute immediate
q'[
select count(*)
from some_table
]'
into v_count;
end test_procedure;
/
If you really do need to manually switch between schemas, then you may want to consider using something like execute immediate 'alter session set current_schema=schema1'; in the procedure and using dynamic SQL for all of the querying.

Is it possible to set default ORACLE dblink for session and avoid #dblink_name suffixes

I have an Oracle database with a couple of public dblinks for various customers. All linked databases for all customers are identical. Also I have a schema on my host machine only, where I stored DB views with some data retrieval logic.
Currently, if I want to retrieve the same data from various customers, I have to create separate almost identical views for every client:
CREATE VIEW my_view_for_cliet1 AS
SELECT *
FROM table1#dblink1;
CREATE VIEW my_view_for_cliet2 AS
SELECT *
FROM table1#dblink2
Is it possible to set default dblink for session (or something similar) and have only one DB view without explicit dblink, for example:
CREATE VIEW my_view AS
SELECT *
FROM table1;
-- below I want to retrieve data from 3rd client
ALTER SESSION SET DEFAULT DBLINK dblink3;
SELECT * FROM my_view;
P.S. I have only SELECT rights on linked machines so I can't create any views or other objects.
No, that is not possible. Every reference to a dblink must be explicit.
Note that each of the other solutions presented (so far) can give the appearance of what you're asking, but still require explicit dblink references in all of the actual views and thus the same DDL changes for every new link and/or client user. There's no way to avoid creating those individual views or explicit references at some level (which is what I believe you were asking), even if you hide them somewhat from the user.
I'd suggest using synonyms, and set up a procedure to change them all at once, e.g.
create or replace procedure SET_DBLINK ( target_link IN VARCHAR2 ) is
begin
execute immediate 'create or replace synonym TABLE1 for TABLE1#' || target_link;
execute immediate 'create or replace synonym TABLE2 for TABLE2#' || target_link;
-- ...etc...
end;
/
That way you could do:
exec SET_DBLINK('dblink3');
select * from table1;
You'd probably want to add validation and exception handling to the procedure, but I left it simple for readability.
For example, user manager
CREATE OR REPLACE VIEW manager.example1 (
column1,
column2
)
AS
select 1, user from dual#dblink1
where 'SCOTT'=user
union all
select 2, user from dual#dblink2
where 'MANAGER'=user
union all
select 3, user from dual#dblink3
where 'HR'=user;
grant select on example1 to scott;
grant select on example1 to hr;
select * from example1;
==>
COLUMN1 COLUMN2
-------------------------------------------- ------------------------------------
2 MANAGER
user scott
create synonym example1 for manager.example1;
select * from example1;
==>
COLUMN1 COLUMN2
-------------------------------------------- ------------------------------------
1 SCOTT
user hr
create synonym example1 for manager.example1;
select * from example1;
==>
COLUMN1 COLUMN2
-------------------------------------------- ------------------------------------
3 HR

Materialized view to be refreshed only when the select query returns data in oracle

Create materialized view mv_testdata
BUILD IMMEDIATE
REFRESH FORCE
AS
SELECT * FROM VW_TESTDATA;
I want the view to be refreshed weekly once and only when the data available in vw_testdata view. Trying with triggers also but it didn't work.
Is it possible to refresh mv only data available in view?
If vw_testdata is an "ordinary" view, it is a stored query and contains no data. I presume your concern is that - if that query (at some time) fetches "nothing" and you refresh the materialized view, you'll lose data in the materialized view.
If that's so, create a stored procedure, e.g.
create or replace procedure p_refresh as
l_cnt number;
begin
select max(1)
into l_cnt
from vw_testdata
where exists (select null from vw_testdata);
if l_cnt = 1 then
dbms_mview.refresh('mv_testdata');
end if;
end;
/
It checks whether anything exists in vw_testadata; if so, it refreshes the materialized view.
Now schedule that procedure to be executed weekly.

How can I find the invisible table in oracle 11g?

There is a table named IM_RESULT_INFO. Because I can see it by SELECT * FROM IM_RESULT_INFO.
But it doesn't exist in table nor view lists in sqldeveloper. I also tested SELECT * FROM all_all_tables and SELECT * FROM dba_tables, and couldn't find the table.
In Eclipse IDE, I searched for it in whole project files, but the only code I found was SELECT ... FROM IM_RESULT_INFO.
I think it is a mixture of tables, but there's no way to analyze it. How can I find it?
It must be a synonym or a view, check the synonyms view to see what object is referenced by it:
SELECT *
FROM all_synonyms
WHERE synonym_name = 'IM_RESULT_INFO'
Or the views view:
SELECT *
FROM all_views
WHERE view_name = 'IM_RESULT_INFO'
You can check in ALL_OBJECTS if you are not sure about the type of an object. It will provide you the Types and other important details also.
For Materialized view please check ALL_MVIEWS.
SELECT *
FROM ALL_OBJECTS
WHERE OBJECT_NAME='IM_RESULT_INFO';

How to add 'WITH READ ONLY' constraint in views in Oracle

I have created a simple view and have forgotten to add WITH READ ONLY while creating the view.
Now I want to alter the view and add WITH READ ONLY option. What will be the query for it?
alter view x read only;
was added in 11.2, but unfortunately only for editioning views.
So there is a chance that in some future version this will be extended to regular views:)
Until that use simple create or replace view
create or replace view x as
select * from dual /* your query */
with read only;
or
create or replace view x as
select * from dual /* your query */
with check option;

Resources