How to grant privilege to a row in Oracle? - oracle

I'm just start learning about Oracle database. I want to ask that how can I grant privilege to a row. For example: employee A just can read, update info about him and he can't read info about employee B or others
Here is my table Employee
create table Employee(
Emp_ID varchar2(20),
Emp_Name varchar2(255),
primary key(Emp_ID)
)

You can add a Data_Owner field to the table populated by the USER function. Don't allow direct access to the table. All access is through a view that exposes only those rows matching the USER value of whoever queries the view. Use the USER function to control the DML.
Here is a sample. Test to see if it meets your needs
create view Sample as
select col_1, col_2, col3
from Sample_Table
where Data_Owner = USER;

Related

Oracle Object Type and Object Table

I have created an object type and a table. I would like to know how select, insert, update and delete operation on it.
create table employee_info (
empid number,
emp_name varchar2(50),
department varchar2(20),
designation varchar2(50),
salary number
);
create type employee_info_obj is object (
empid number,
department varchar2(50),
designation varchar2(50),
salary number
);
create type employee_info_obj_t is
table of employee_info_obj ;
You have only created an object type and an unrelated database table. If you want a database table based on the type, you need to create one:
create table employee_info of employee_info_obj;
While it can be nice in certain programming scenarios to have a type synced to a table, there are some downsides such as it being harder to add columns later, and third party tool support since the object table will not be listed in user_tables but only in user_object_tables and user_all_tables, so I would question the usefulness of this approach.
dbFiddle

How to check if table has specific grants before inserting a record in a table?

Scenario: I have a config table which includes meta-data about log tables (e.g. Table_name, table_owner). I want to add a trigger to this config table which essentially checks if the table record that is to be inserted, has the specific grant (delete) if not, then don't allow that to happen. How can I go about this?
Another way to do it is to forget about triggers but use a VIEW...WITH CHECK OPTION to control that no one inserts data they shouldn't.
Suppose your config table looks like this:
CREATE TABLE my_config
( owner VARCHAR2(30) NOT NULL,
table_name VARCHAR2(30) NOT NULL,
other_stuff VARCHAR2(500),
CONSTRAINT my_config_pk PRIMARY KEY ( owner, table_name ) );
Create a view to handle inserts
The conditions of the view limit it to only include tables on which the current user has DELETE privileges.
The WITH CHECK OPTION will ensure than no one may use the view to insert or update data that does not satisfy the view.
CREATE VIEW my_config_ins_v
AS
SELECT * FROM my_config c
WHERE EXISTS ( SELECT 'user has delete privs'
FROM user_tab_privs p
WHERE p.owner = c.owner
AND p.grantee = user
AND p.table_name = c.table_name
AND p.privilege = 'DELETE' )
WITH CHECK OPTION;
Try it out
INSERT INTO my_config_ins_v VALUES ('USER_1','TABLE_I_HAVE_ACCESS_TO', 'STUFF');
-- 1 row inserted.
INSERT INTO my_config_ins_v VALUES ('SYS','OBJ$', 'STUFF');
-- ORA-01402: view WITH CHECK OPTION where-clause violation
Naturally, for this to be effective, you cannot
GRANT INSERT ON my_config TO anyone; -- don't do this
Instead:
GRANT INSERT ON my_config_ins_v TO anyone;

Table tablespace shown as X but appears to be 'Users'

I am using SQL*Plus to create a table with the following sql:
CREATE TABLE SCHEMA_OWNER.TEST_TABLE (
ID NUMBER(19,0) NOT NULL,
TEST_STRING VARCHAR2(255 CHAR),
PRIMARY KEY (ID)
);
When I try and do an insert with any user into that table, I see the following error:
INSERT INTO TEST_TABLE (ID, TEST_STRING) values (1, 'Test')
ORA-01950: no privileges on tablespace 'USERS'
This implies that the table has been created in the Users tablespace, but when I look in the USER_TABLES table, I see that the tablespace is the same as all of the other tables, and not 'Users':
SELECT table_name, tablespace_name from USER_TABLES;
TABLE_NAME TABLESPACE_NAME
---------------- ---------------
TABLE1 DATA_TABLESPACE
TEST_TABLE DATA_TABLESPACE
When I create the table in SQL developer using the same SQL, I don't have any errors when inserting data.
1) Why am I getting this error when the table isn't in the Users tablespace?
2) Why am I only getting it when running the sql script from SQL*Plus?
Thanks to Aleksej for suggesting it could be an issue with the indexes. The problem was that when I was creating the index on the table, I wasn't creating it for the schema owner, which meant that it was being created in a different tablespace.
So instead of
CREATE INDEX TEST_TABLE_IDX ON SCHEMA_OWNER.TEST_TABLE(TEST_STRING);
I needed to do
CREATE INDEX SCHEMA_OWNER.TEST_TABLE_IDX ON SCHEMA_OWNER.TEST_TABLE(TEST_STRING);

How to duplicate all data in a table except for a single column that should be changed

I have a question regarding a unified insert query against tables with different data
structures (Oracle). Let me elaborate with an example:
tb_customers (
id NUMBER(3), name VARCHAR2(40), archive_id NUMBER(3)
)
tb_suppliers (
id NUMBER(3), name VARCHAR2(40), contact VARCHAR2(40), xxx, xxx,
archive_id NUMBER(3)
)
The only column that is present in all tables is [archive_id]. The plan is to create a new archive of the dataset by copying (duplicating) all records to a different database partition and incrementing the archive_id for those records accordingly. [archive_id] is always part of the primary key.
My problem is with select statements to do the actual duplication of the data. Because the columns are variable, I am struggling to come up with a unified select statement that will copy the data and update the archive_id.
One solution (that works), is to iterate over all the tables in a stored procedure and do a:
CREATE TABLE temp as (SELECT * from ORIGINAL_TABLE);
UPDATE temp SET archive_id=something;
INSERT INTO ORIGINAL_TABLE (select * from temp);
DROP TABLE temp;
I do not like this solution very much as the DDL commands muck up all restore points.
Does anyone else have any solution?
How about creating a global temporary table for each base table?
create global temporary table tb_customers$ as select * from tb_customers;
create global temporary table tb_suppliers$ as select * from tb_suppliers;
You don't need to create and drop these each time, just leave them as-is.
You're archive process is then a single transaction...
insert into tb_customers$ as select * from tb_customers;
update tb_customers$ set archive_id = :v_new_archive_id;
insert into tb_customers select * from tb_customers$;
insert into tb_suppliers$ as select * from tb_suppliers;
update tb_suppliers$ set archive_id = :v_new_archive_id;
insert into tb_suppliers select * from tb_suppliers$;
commit; -- this will clear the global temporary tables
Hope this helps.
I would suggest not having a single sql statement for all tables and just use and insert.
insert into tb_customers_2
select id, name, 'new_archive_id' from tb_customers;
insert into tb_suppliers_2
select id, name, contact, xxx, xxx, 'new_archive_id' from tb_suppliers;
Or if you really need a single sql statement for all of them at least precreate all the temp tables (as temp tables) and leave them in place for next time. Then just use dynamic sql to refer to the temp table.
insert into ORIGINAL_TABLE_TEMP (SELECT * from ORIGINAL_TABLE);
UPDATE ORIGINAL_TABLE_TEMP SET archive_id=something;
INSERT INTO NEW_TABLE (select * from ORIGINAL_TABLE_TEMP);

Setting the primary key of a object type table in Oracle

I have two Oracle questions.
How can I set the primary key of a table when the table is made up of an object type? e.g.
CREATE TABLE object_names OF object_type
I have created a Varray type,
CREATE TYPE MULTI_TAG AS VARRAY(10) OF VARCHAR(10);
but when I try to do
SELECT p.tags.count FROM pg_photos p;
I get an invalid identifier error on the "count" part. p.tags is a MULTI_TAG, how can I get the number of elements in the MULTI_TAG?
First of all I wouldn't recommend storing data in Object tables. Objects are a great programmatic tool but querying Object tables leads to complicated SQL. I would advise storing your data in a standard relationnal model and using the objects in your procedures.
Now to answer your questions:
A primary key should be immutable, so most of the time an Object type is inappropriate for a primary key. You should define a surrogate key to reference your object.
You will have to convert the varray into a table to be able to query it from SQL
For example:
SQL> CREATE TYPE MULTI_TAG AS VARRAY(10) OF VARCHAR(10);
2 /
Type created
SQL> CREATE TABLE pg_photos (ID number, tags multi_tag);
Table created
SQL> INSERT INTO pg_photos VALUES (1, multi_tag('a','b','c'));
1 row inserted
SQL> INSERT INTO pg_photos VALUES (2, multi_tag('e','f','g'));
1 row inserted
SQL> SELECT p.id, COUNT(*)
2 FROM pg_photos p
3 CROSS JOIN TABLE(p.tags)
4 GROUP BY p.id;
ID COUNT(*)
---------- ----------
1 3
2 3
1)
A primary key is a constraint, to add constrains on object tables check this link:
http://download-west.oracle.com/docs/cd/B28359_01/appdev.111/b28371/adobjdes.htm#i452285
2)
The COUNT method can't be used in a SQL statement:
REF LINK IN COMMENTS
So in my case I had to do
SELECT p.pid AS pid, count(*) AS num_tags FROM pg_photos p, TABLE(p.tags) t2 GROUP BY p.pid;

Resources