Oracle Users Tables - sql

I've created some TABLES in 1 DB with the user name DEVICE.
Querying the tables I see that they belong to the user DEVICE
SELECT owner, table_name FROM dba_tables
Then I created a user named CAR, I logged in the DB with that user and create some tables, I've tried to query the other tables with
SELECT * FROM DEVICE.table_name;
with the result
00942. 00000 - "table or view does not exist"
and logged with the user CAR and don't see the user DEVICE in others users from SQL Developer

This error comes up because CAR doesn't have privileges to query the DEVICE's table.
You need to grant access to this table to CAR.
1- login as DEVICE
2- Issue the following grant:
GRANT SELECT ON TABLE_NAME TO CAR;
If you want to do it for all the tables of the DEVICE user, create a script like that:
select 'GRANT SELECT ON ' || table_name || ' TO CAR;' FROM USER_TABLES;
My advice would be to create a ROLE if you do that:
CREATE ROLE DEVICE_READ_ROLE;
select 'GRANT SELECT ON ' || table_name || ' TO DEVICE_READ_ROLE;' FROM USER_TABLES;
GRANT DEVICE_READ_ROLE TO CAR;
Note that if you create new tables in the DEVICE schema you will need to grant select on the new table to the ROLE for CAR to have access to it.

Here the script to generate grant select on all the tables.
select 'grant select on Admin.' || object_name || ' to User;'
from user_objects
where object_type in('TABLE');
Then you have to create a script to run these grant statements at once or you can use PL/SQL as well. Type the following in the SQL prompt.
SQL> spool grant_statements.sql
SQL> set pagesize 0
SQL> set feedback off
SQL> set linesize 300
SQL> set trimout on
SQL> set trimspool on
SQL> select 'grant select on Admin.' || object_name || ' to User;' from user_objects where object_type in('TABLE','SYNONYM')
/
SQL> spool off
And you have got the script file you can run it.
OR
You can run the following PL/SQL block (Run as admin user).
BEGIN
FOR s IN (SELECT *
FROM user_objects where object_type in('TABLE','SYNONYM'))
LOOP
EXECUTE IMMEDIATE 'grant select on admin.' || s.object_name || ' to user';
END LOOP;
END;

you need to grant access to user CAR for the tables created by DEVICE . login using DEVICE user and grant access to the tables CAR should be able to access using sql like below
GRANT SELECT , UPDATE , INSERT ON TABLE_NAME TO CAR;

Related

Want to grant select to a specific user on all tables

I use the below to grant select permission to amy on table1:
grant select schema.table1 to amy;
However, the below does not work:
grant select on schema.* to amy;
the error is
ORA-00903: invalid table name
Please advise what is wrong in my command. What I want is grant select to amy on ALL tables.
thanks
The syntax for the GRANT command (as of Oracle 21c) makes it clear that the granted item can only be a specific object:
on_object_clause:
The best you can do is create a role and grant the role to Amy, but you will still have to grant privileges on each individual table to the role.
create role analyst;
grant analyst to amy;
grant read on hr.countries to analyst;
grant read on hr.departments to analyst;
grant read on hr.employees to analyst;
To create a role and grant it to amy:
create role select_all_tables;
grant select_all_tables to amy;
alter user amy default role select_all_tables;
Use the following query to generate a script, which you can copy/paste and run to complete all the grants:
select 'grant select on '|| owner || '.' || table_name ||' to select_all_tables;'
from dba_tables where owner='SCHEMA';
copy and paste the output, and execute it as as script.
grant select on schema.table1 to select_all_tables;
grant select on schema.table2 to select_all_tables;
...
If you would rather grant the privileges directly and not use a role, alter the script query:
select 'grant select on '|| owner || '.' || table_name ||' to amy;'
from dba_tables where owner='SCHEMA';
and then run the output as a script:
grant select on schema.table1 to amy;
grant select on schema.table2 to amy;
...
grant select on table to public;
But be careful when you do that -- make sure it's what you really want to do.

In Oracle, Can you create a new table with the same groups if you use CTAS Query?

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

Dropping postgres role and database after many grants

I'm trying to efficiently drop role from a postgres instance, and running into some problems. I'm looking for some SQL to drop role so that I can stop reading error messages and don't have to do this manually.
In the setup I'm working in, every roles gets its own database of the same name:
CREATE ROLE alpha_user;
CREATE DATABASE alpha_user;
ALTER DATABASE alpha_user OWNER TO alpha_user;
Users often grant access to schemas in their database to other users:
-- alpha_user logs in to the alpha_user database
GRANT USAGE ON SCHEMA myschema TO beta_user;
When I attempt to drop beta_user, this happens:
-- log in as superuser
DROP ROLE beta_user;
-- ERROR: role "beta_user" cannot be dropped because some objects depend on it
-- DETAIL: N objects in database alpha_user
I can connect to the alpha_user database, and drop OWNED BY, but this is inefficient:
-- log in as superuser
\c alpha_user;
DROP OWNED BY beta_user CASCADE;
DROP beta_user;
-- success
Users can grant access to any number of databases, and there are many users. Is there a statement (or series of statements) that a super user can execute to DROP OWNED BY for a user across all databases where the user has been granted access?
Maybe this will help you:
with
user_id as (select oid, rolname as my_user from pg_authid where rolname in('abc', 'xyz'))
select 'REVOKE ' || rolname || ' FROM ' || my_user || ' CASCADE;' as sql
from pg_auth_members
join pg_authid on pg_auth_members.roleid = pg_authid.oid
JOIN user_id ON pg_auth_members.member = user_id.oid
union
SELECT 'REVOKE ALL ON ' || datname || ' FROM ' || my_user || ' CASCADE;'
FROM pg_database
JOIN user_id ON pg_database.datdba = user_id.oid

Select access to all tables

In oracle 11g, I have a owner schema which contains the relevant tables required for an app.
For my external application i am trying to create another user which should have select access on certain tables to the above schema.
Lets call the owner schema A and the new schema B
create user B identified by blah;
grant connect to B;
After logging into the original schema A i ran the following (for demo i am giving select on all tables)
begin
FOR x IN (select * from user_tables)
LOOP
EXECUTE IMMEDIATE 'GRANT SELECT ON ' || x.table_name || ' TO some_role';
END LOOP;
end;
grant some_role to B;
If i login as user B and execute a query like
select count(*) from A.some_table ;
it works. But without creating a public synonym is it possible for me to grant
in such a way that the following works when logged in as user B?
select count(*) from some_table;
Thanks
You can create private synonyms for user B to use.
As user B, run the following block:
begin
FOR t IN (SELECT * FROM role_tab_privs WHERE grantee = 'SOME_ROLE' and owner = 'A')
LOOP
EXECUTE IMMEDIATE 'CREAETE SYNONYM ' || table_name || ' FOR A.' || table_name';
END LOOP;
end;
if you are just reading data from tables owned by userB, you can set below command and run SELECT on tables as if they were in userA schema:
alter session set current_schema=userB
(logged as UserA)
Then below two commands will be equivalent (have same result):
select ... from userB.TABLE1
select ... from TABLE1
GRANT SELECT ANY TABLE TO YOUR_USER_OR_ROL;

Revoking Oracle Permissions to multiple users at once

We're rationalising our database user permissions and to that end we'd like to revoke all select permissions across all tables in a schema granted to all users (but not a specific role).
With some regular expressions I've tried creating a universal revoke for each table giving something like:
revoke select on TABLE1 from USER1,USER2,USER3...;
revoke select on TABLE2 from USER1,USER2,USER3...;
However as not all users were granted permissions to all tables, this results in the oracle error:
01927. 00000 - "cannot REVOKE privileges you did not grant"
Which makes sense but isn't helpful.
I also tried using All_Tab_Privs to get a list of all tables with the requisite grants to be revoked, and this works, but I can't see how to easily get from this to actually revoking the permissions.
SELECT * From All_Tab_Privs where grantor = 'GRANTING_USER' and grantee != 'READROLE' and grantee != 'PUBLIC' and grantee != 'SYS';
Any suggestions for how to do this without spending hours in a spreadsheet? I'm guessing some PL/SQL? Thanks.
A general pattern for this kind of job is to use an implicit cursor to return the data you want and then to build the DDL and execute them.
begin
for x in (select attribute_1, attribute_2 ... from ... where ...)
loop
execute immediate 'REVOKE ...'||x.attribute1||' etc';
end loop;
end;
/
A nice alternative is to build the SQL you want to execute in the SELECT and then just execute that. It's easier to test but the SQL then looks a bit clunky.
-- Revoke Privs Granted to Users
BEGIN
FOR r IN (SELECT * FROM all_tab_privs WHERE grantee IN ('USER_1', 'USER_2'))
LOOP
EXECUTE IMMEDIATE 'REVOKE '||r.privilege||' ON '||r.table_name||' FROM '||r.grantee;
END LOOP;
END;
/
Some PL/SQL and dynamic SQL:
begin
for r in (SELECT * From All_Tab_Privs
where grantor = 'GRANTING_USER'
and grantee != 'READROLE'
and grantee != 'PUBLIC'
and grantee != 'SYS')
loop
execute immediate 'revoke '||r.privilege||' from '||r.grantee;
end loop;
end;
I had a quite interesting situation on my database. Oracles own SQL Developer still listed the existing grants for each table, although they were gone from the all_tab_privs table (a SELECT brought no result for the searched grantees).
I've fixed that by using the following construct:
BEGIN
FOR r IN (SELECT owner, table_name FROM dba_tables WHERE owner IN ('owner1', 'owner2'))
LOOP
EXECUTE IMMEDIATE 'REVOKE ALL ON '||r.owner||'.'||r.table_name||' FROM grantee1, grantee2';
END LOOP;
END;
/
This first selects all owners and table names from each table of certain owners. Then it revokes all grants for certain grantees.
The good thing is, that this won't fail if there aren't any grants for one of the listed grantee for one of the selected tables.
Mind that this should be executed from an administrator account, like system, so the current user has the right to revoke grants for tables of another user.