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;
Related
Is it possible to se the results of a sql query in a Proc, for example I'm looking to automate Grant's on Roles to certain tables.
SELECT DISTINCT 'GRANT SELECT ON '|| TABLE_NAME ||' TO BI_PUBLISHED_ACCESS;'
FROM BI.dd_tables
WHERE PUBLISHED = 'Y';
Output:-
GRANT SELECT ON TABLE1 TO BI_PUBLISHED_ACCESS;
GRANT SELECT ON TABLE2 TO BI_PUBLISHED_ACCESS;
GRANT SELECT ON TABLE3 TO BI_PUBLISHED_ACCESS;
AND SO ON
I then copy & paste the output back into the worksheet & run the full script to grant select on all of my published table to the BI_PUBLISHED_ACCESS Roll.
My process works but it is a very manual operation. My question is can I use the output of one query to run another one?
You can use EXECUTE IMMEDIATE statement.
So, the solution will looks like:
BEGIN
for grant_statement in
(SELECT DISTINCT 'GRANT SELECT ON '|| TABLE_NAME ||' TO BI_PUBLISHED_ACCESS;'
FROM BI.dd_tables
WHERE PUBLISHED = 'Y')
LOOP
EXECUTE IMMEDIATE grant_statement;
END LOOP;
END;
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;
Our company is using Oracle 11g (11.2.0.5.0)
I'm looking for a way to execute external query (in this specific example called from PHP website) that would FOR LOOP through set of data and return results in the form of table (like normal SELECT would)
USERS table:
DB1
DB2
DB3
...
DBO
Each user's schema contains ITEM table:
ID CODE TYPE
--------------------
1 0001 A
2 0043 A
3 00A5 V
...
I want to execute a query that would loop through all USERS and fetch data from their ITEM tables, something along lines of my not working
FOR user IN (SELECT * FROM all_users)
LOOP
SELECT CODE, user FROM user.ITEM_TABLE WHERE TYPE = 'V'
END LOOP;
That would return
CODE USER
-------------
00A5 DB1
0434 DB2
0999 DB2
...
If I correctly understand your need, maybe this can help:
declare
type tabUser is table of varchar2(30);
type tabCode is table of varchar2(30);
vTabCode tabCode;
vTabUser tabUser;
vSQL varchar2(32767);
begin
select listagg('select code, ''' || owner || ''' from ' || owner || '.item_table where type = ''V''', ' UNION ALL ')
within group (order by owner)
into vSQL
from dba_tables where table_name = 'ITEM_TABLE';
--
dbms_output.put_line(vSQL);
--
execute immediate vSQl bulk collect into vTabCode, vTabUser;
--
/* ... what you need to do with your data */
end;
/
I removed all_users, given that probably there are users that do not have the ITEM_TABLE table, for example SYS; in this way you only query for really existing tables.
The first part dynamically builds the query you need, by concatenating queries from different users; in the second part you have your data extracted from all the tables, so you can do whatever you need.
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
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.