Are SCHEMA and USER the same thing in Oracle? - sql

Are SCHEMA and USER the same thing in Oracle? Is there is situation where a single user can have two or more schemas?

Strictly speaking a SCHEMA is the set of objects owned by a USER. However, a USER can have only one SCHEMA, so people often use the terms interchangeably.
Here's the difference between USER and SCHEMA. User "A" has granted rights on its PRODUCT table to user "B". User "B" does not have a table of that name.
SQL> show user
USER is "B"
SQL> select count(*) from products
2 /
select count(*) from products
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select count(*) from a.product
2 /
COUNT(*)
----------
2
SQL>
Without a synonym "B" needs to prefix the schema to reference the PRODUCT table. Unless they choose to change the current schema:
SQL> alter session set current_schema = "A"
2 /
Session altered.
SQL> select count(*) from product
2 /
COUNT(*)
----------
2
SQL> show user
USER is "B"
SQL>
Now the user is "B" but the current (default) schema is "A". Which menas they need to prefix the schema when referencing their own tables!
SQL> select table_name from user_tables;
TABLE_NAME
------------------------------
YOUR_TABLE
SQL> select count(*) from your_table;
select count(*) from your_table
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select count(*) from b.your_table;
COUNT(*)
----------
6
SQL>
"Whether a schema can be created separately Without any user ."
No. A SCHEMA must belong to a USER. When we create user Oracle creates a schema, an empty one, automatically.
Confusingly there is a create schema syntax, but that is just a short hand for creating a number of tables (and indexes) in one statement. Find out more.

Related

Role to access the table only but not data from Table in Oracle Exadata

Users have create table statement with select statement from multiple tables from multiple schema. I want to restrict them to read data and allow them to create empty table in their schema with metadata only not data. This I want to do at user access and roles level.
Please tell me how I can do this?
I have tried giving them read access on underlying tables but users can see data as well.
Create table cust_acct_details
as
select *
from ep_rel.acct a
inner join ep_dnf.Cust_account ca
on a.acct_id = ca.acct_id
Tables should create without data.
Add below condition to your code
-- condition to add where 1<>1
Create table cust_acct_details
as
select *
from ep_rel.acct a
inner join ep_dnf.Cust_account ca
on a.acct_id = ca.acct_id
where 1<>1
Please make sure there are unique column names in your select statement. Oracle will not allow same column name in one table. Please use alias instead of *.
If you remove all tablespace privileges from a user they can still create tables but they won't be able to populate them.
For example, if you run this PL/SQL block to revoke all tablespace quotas from one user:
begin
for users in
(
select 'alter user '||username||' quota 0 on '||tablespace_name v_sql
from dba_ts_quotas
where username = 'TEST_USER'
order by 1
) loop
execute immediate users.v_sql;
end loop;
end;
/
Now the user can create tables but will get an error if they try to add rows:
SQL> create table test1(a number);
Table created.
SQL> insert into test1 values(1);
insert into test1 values(1)
*
ERROR at line 1:
ORA-01536: space quota exceeded for tablespace 'USERS'
For metadata, users can always see the metadata in their own schema. To allow them to view the metadata in other schema, run a grant like:
grant select_catalog_role to the_user;
Then that user can view the metadata either in the ALL_ data dictionary views, or using DBMS_METADATA.GET_DDL.

Dual table issue

Hi We all know DUAL is the table of SYS and other users have synonym of it.
but when i fire the below commnad
create table dual(x varchar2(1));
it worked. An object of the name DUAL was created.
when there is already a synonym with the name DUAL how can we create another object of same name? why oracle is allowing us to do it.
You can create a table named DUAL because tables and public synonyms have a different namespace. For details, see chapter Database Object Names and Qualifiers of Oracle's SQL Language Reference.
EDIT: To illustrate the mechanism:
If you create your own DUAL table as user scott
CREATE TABLE dual (x VARCHAR2(1));
... then it shows up in the data dictionary:
SELECT object_id, object_type, owner, object_name, namespace
FROM dba_objects
WHERE object_name='DUAL';
OBJECT_ID OBJECT_TYPE OWNER OBJECT_NAME NAMESPACE
142 TABLE SYS DUAL 1
143 SYNONYM PUBLIC DUAL 1
78138 TABLE SCOTT DUAL 1
So, the names are unique per owner and namespace. You cannot add yet another table in your schema called DUAL. You cannot create a private synonym named DUAL, but you can create your own synonym for schemas in other objects.
Please make sure to drop the table again. Even simple statements won't work anymore:
SELECT sysdate FROM DUAL;
--
DROP TABLE dual;
SELECT sysdate FROM DUAL;
01.07.2018
I think DUAL is a distraction here. Of course it's a system table and there are side effects if you mess about with it, so don't. But the question is really about why there is no namespace conflict between any object and a public synonym with the same name. For example, I can create a table named ALL_TABLES or DBMS_OUTPUT in my own schema (if I really want to). Or, I can create a table called MYDEMOTABLE and then create a public synonym MYDEMOTABLE for WILLIAM.MYDEMOTABLE.
But then, what restriction are you expecting to exist? There is already both a table (owned by SYS) and a public synonym (owned by PUBLIC) named DUAL. You can create a third object with the same name, as long as it isn't owned by SYS or PUBLIC.
I think I found a way to demonstrate what is going on (without using DUAL or any other SYS object ;-):
If two users create a table with the same name, the tables end up in their own schema as expected:
CREATE USER user_a IDENTIFIED BY user_a;
CREATE USER user_b IDENTIFIED BY user_b;
CREATE TABLE user_a.foo (x NUMBER);
CREATE TABLE user_b.foo (x NUMBER);
SELECT object_id, object_type, owner, object_name, namespace
FROM dba_objects
WHERE object_name='FOO';
OBJECT_ID OBJECT_TYPE OWNER OBJECT_NAME NAMESPACE
78225 TABLE USER_A FOO 1
78226 TABLE USER_B FOO 1
But when one of them creates a public synonym (as SYS did with it's DUAL table), it ends up in a magic schema with the name PUBLIC:
CREATE PUBLIC SYNONYM foo FOR user_a.foo;
SELECT object_id, object_type, owner, object_name, namespace
FROM dba_objects
WHERE object_name='FOO';
OBJECT_ID OBJECT_TYPE OWNER OBJECT_NAME NAMESPACE
78225 TABLE USER_A FOO 1
78226 TABLE USER_B FOO 1
78156 SYNONYM PUBLIC FOO 1
So, in other words, public synonyms are just synonyms that live in the schema PUBLIC. And you can have only one table, view, sequence, package, synonym with the same name per schema.
There have various schemas in your single database. When you asked about default DUAL table, which actually belongs to 'sys' Schema which is system schema. But your default Database schema is dbo it means when you have executed your query to create DUAL table is actually created in your default schema named dbo.
If you want to check their actual double existence there are many ways to check.
You can apply a query like "select * from sys.DUAL" and "select * from dbo.DUAL". there you will see two different outputs.
you can check all the schemas in "select * from sys.schemas".
Also, you can check their different schemas in with table name
"select * from sys.tables where name ='DUAL'";
the result will be two different tables with two different schema Id's.
Hope this will help you to understand schema basics.

Oracle SQL - Column has no Corresponding Table

I came across something that makes no sense.
This is the SAAADMS form containing the Curriculum tab. The form has fields (columns) from different sources (tables). Most of these columns have a corresponding table, but the User ID and Activity Date (in the red rectangle) do not have a corresponding table!
You can see that the SOVLCUR_ACTIVITY_DATE and SOVLCUR_USER_ID do not have a corresponding table. It states "N/A." The other two columns I listed (I only listed a couple since there are several) do have a corresponding table.
I am trying to pull data from the two columns with no corresponding table.
The SOVLCUR table I currently have in the code does NOT exist.
How do I find where this SOVLCUR_USER_ID and SOVLCUR_ACTIVITY_DATE data is stored or pull from a column that seems to have no table?
If the data is not really stored in SOVLCUR_USER_ID and SOVLCUR_ACTIVITY_DATE is there a way for me to see where it is stored? find all associated columns?
SELECT
SP.SPRIDEN_ID AS "STUDENT_ID",
SP.SPRIDEN_LAST_NAME AS "LAST",
SP.SPRIDEN_FIRST_NAME AS "FIRST",
SD.SARADAP_TERM_CODE_ENTRY AS "TERM",
SD.SARADAP_APPL_DATE AS "APP_DATE",
SV.SOVLCUR_USER_ID AS "USER_ID", /*SOVLCUR table does not exist*/
SV.SOVLCUR_ACTIVITY_DATE AS "ACTIVITY_DATE", /*SOVLCUR table does not exist*/
SYSDATE
FROM
SPRIDEN SP
JOIN SARADAP SD
ON SPRIDEN_PIDM = SARADAP_PIDM
JOIN SOVLCUR SV /*This table does not exist*/
ON SPRIDEN_PIDM = SOVLCUR_PIDM
WHERE
SP.SPRIDEN_CHANGE_IND IS NULL
AND
SD.SARADAP_TERM_CODE_ENTRY >= '201510'
AND
SV.SOVLCUR_USER_ID NOT IN ('SSmith', 'JJones')
AND
SV.SOVLCUR_ACTIVITY_DATE BETWEEN SYSDATE-1 AND SYSDATE
Oracle provides views/tables that can be query to find out that type of information:
select table_name from all_tab_columns
where column_name = 'COLUMN NAME';
This query will return all the table where that column exists.
As user1261620 said, use ALL_TAB_COLUMNS to see the table_name corresponding to a column_name. But, as you say that few tables does not exist, perhaps, those are not tables, rather VIEWS.
To confirm whether those are TABLE or VIEW, you can query ALL_OBJECTS
SELECT object_name, object_type
FROM all_objects
WHERE object_name = 'SOVLCUR';
If the above returns no rows, that would mean the object really doesn't exist. But, in that case the query won't be executed, as it won't be parsed at all. You would get error : table/view does not exist`.
Also, not all values needs to be always stored in database. The computed values are generally calculated through a query and returned to the user for display. And other than computed values, few static values like SYSDATE can be dynamically generated rather than storing it in database and querying it.
So, I think, those are not tables, rather VIEWS. Follow the steps as I mentioned to have a clear understanding.
Update Based on OP's new inputs
So, now you know that SOVLCUR is a synonym. Execute the following query to see its details :
SELECT * FROM all_synonyms WHERE synonym_name = 'SOVLCUR';
For example,
I am user LALIT, and I create a synonym for EMP table in SCOTT schema.
SQL> show USER
USER is "LALIT"
SQL>
SQL> CREATE OR REPLACE SYNONYM lalit FOR scott.emp
2 /
Synonym created.
SQL>
SQL> SELECT owner, synonym_name, table_owner, table_name
2 FROM all_synonyms
3 WHERE synonym_name = 'LALIT'
4 /
OWNER SYNONYM_NAME TABLE_OWNER TABLE_NAME
---------- --------------- ------------ ----------
LALIT LALIT SCOTT EMP
So, the table_owner and table_name shows the SCHEMA is SCOTT and TABLE is EMP.

SQL Table does not exist

This is what happens:
SQL> select table_name from user_tables;
TABLE_NAME
------------------------------
Discount
Taxes
Customer
Vehicles
WorkOrder
Task
TaskPart
Employee
EmplyeeTask
WorkOrderPart
InvoiceDetails
TABLE_NAME
------------------------------
Invoice
Parts
InvoicePrimaries
14 rows selected.
SQL> select * from Discount;
select * from Discount
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL>
I can't access that table. I can make it work just fine in C#, but in the Oracle GUI and the SQL Command Line, I cannot select the table. (It's a personal, self made database using Oracle Express)
Because in user_tables the table names are written in upper and lower case letters. I assume that you created these tables using something like
create table "Discount" ...
Generally oracle saves tablenames in upper case letters and table names without double quotas are searched in uppercase. Therefore your
select * from Discount
searches for a table named DISCOUNT and not Discount. You have to explicitly tell oracle that you want to preserve the letter case of your table names. That is done with double quotas as well. So
select * from "Discount"
should work.

SQL Database Restrict View of Data

Okay so I am new to SQL and was just wondering if there where a way to limit who would have access to what type of data in terms of when retriving information from the tables. Like for example I had a table with information about a client which would have his name, phone, address, SSN, salary, and etc. I want to figure out if there is a way to limit what is being shown based on who is viewing that data. As in a Person A can see everything while Person B can see everything except for SSN and Salary
EDIT:
Could the use of a trigger to limit the view of a certain group work?
You can use views. After that it depends on usage, how the persons access to data (some access rights or user groups etc.)
To make columns not appear for certain users, you'd either need distinct views for each user group (ie view A that didnt have SSN, salary for users in the restricted group etc). or use fine grained access control
FGAC: http://docs.oracle.com/cd/B19306_01/network.102/b14266/apdvcntx.htm
fine grained access control applies straight to the table, so you wouldn't need views to implement that.
e.g. a very simple test to show you. lets say anyone with the Oracle role "SSN_AUTH" can view SSN/Salary for all rows. those without it,cannot.
SQL> create table person(id number, name varchar2(200), ssn varchar2(20), salary number(*,2));
Table created.
now we create a function (by all means, put this in a package for real code). the function will apply a silent predicate exists (select null from session_roles where role = 'SSN_AUTH') for every query fired on the person table. i.e. that predicate will mean that if you don't have an enabled role called SSN_AUTH, you won't see the data.
SQL> create or replace function person_rls (p_owner in varchar2, p_name in varchar2)
2 return varchar2 as
3 v_sql varchar2(2000);
4 begin
5 v_sql := 'exists (select null from session_roles where role = ''SSN_AUTH'')';
6 return v_sql;
7 end person_rls;
8 /
Function created.
now, i dont want to supress rows (though we could do). we just want to supress column data. so we add this function as a policy to the table and tell it the columns to secure:
SQL> BEGIN
2 DBMS_RLS.ADD_POLICY(object_schema=>user, object_name=>'PERSON',
3 policy_name=>'SEC_PERSON', function_schema=>user,
4 policy_function=>'PERSON_RLS',--our function
5 sec_relevant_cols=>'ssn,salary', -- secure these cols.
6 sec_relevant_cols_opt=>dbms_rls.ALL_ROWS);
7 END;
8 /
PL/SQL procedure successfully completed.
SQL> insert into person values (1, 'DazzaL', 'asdklakjd', 10000.12);
1 row created.
SQL> commit;
Commit complete.
now if we don't have the role set:
SQL> set role none;
Role set.
SQL> select * from person;
ID NAME SSN SALARY
---------- -------------------- -------------------- ----------
1 DazzaL
the salary + SSN is blank..but if we enable the role.
SQL> set role all;
Role set.
SQL> select * From session_roles;
ROLE
------------------------------
CONNECT
RESOURCE
SELECT_CATALOG_ROLE
HS_ADMIN_SELECT_ROLE
PLUSTRACE
SSN_AUTH <--- we have it now.
SQL> select * from person;
ID NAME SSN SALARY
---------- -------------------- -------------------- ----------
1 DazzaL asdklakjd 10000.12
the data magically appears.