Oracle - denie columns in where clause - oracle

Is there a way to disable/restrict/alert-when-using some column in Oracle in a where clauses?
The reason that I'm asking this is because I have a very complex system (~30 services span cross millions of lines of code with thousends of sqls in it, in a sensitive production environment) working with an Oracle DB I need to migrate from using one column that is part of a key (and have a very not uniqu name) to another column.
Simple search is impossible....
The steps I'm having are:
populate new column
Add indexes on with the second column whenever there's an index with the first one.
Migrate all uses in where caluses from old to new column
Stop reading from the first column
Stop writing to the first column
Delete the column
I'm currently done step 3 and want to verify I've found all of the cases.

So, you're replacing one column with another. Which benefit do you expect once you're done? How will that improve overall experience with that application? I hope it is worth the effort.
As of your question: query user_source (or expand it to all_source or even dba_source, but you'll need additional privileges to do that) and see where's that very not unique name used. Something like this:
SQL> select * from user_source where lower(text) like '%empno%';
NAME TYPE LINE TEXT
--------------- ------------ ----- --------------------------------------------------------------------------------
P_RAISE PROCEDURE 22 WHERE empno = par_empno;
P_RAISE PROCEDURE 14 WHERE empno = par_empno;
P_RAISE PROCEDURE 1 PROCEDURE p_raise (par_empno IN emp.empno%TYPE)
GET_LIST FUNCTION 7 'select empno, ename, job, sal from emp where deptno = 10 order by '
SQL>

Related

Is it possible to add a custom metadata field to Oracle Data Dictionary?

Is it possible to add a metadata field at column-level (in the Oracle Data Dictionary)?
The purpose would be to hold a flag identifying where individual data items in a table have been anonymised.
I'm an analyst (not a DBA) and I'm using Oracle SQL Developer which surfaces (and enables querying of) the COLUMN_NAME, DATA_TYPE, NULLABLE, DATA_DEFAULT, COLUMN_ID, and COMMENTS metadata fields of our Oracle DB (see pic).
I'd be looking to add another metadata field at this level (essentially, to add a second 'COMMENTS' field) to hold the 'Anonymisation' flag, to support easy querying of our flagged-anonymised data.
If it's possible (and advisable / supportable), I'd be grateful for any advice for describing the steps required to enable this, which I can then discuss with our Developer and DBA.
Short answer: NO.
But where could you keep that information?
In your data model.
Oracle provides a free data modeling solution, Oracle SQL Developer Data Modeler. It provides the ability to mark table/view columns as sensitive or PII.
Those same models can be stored back in your database so they can be accessed via SQL.
Once you've marked up all of your sensitive attributes/columns, and store it back into the database, you can query it back out.
Disclaimer: I work for Oracle, I'm the product manager for Data Modeler.
[TL;DR] Don't do it. Find another way.
If it's advisable
NO
Never modify the data dictionary; (unless Oracle support tells you to) you are likely to invalidate your support contract with Oracle and may break the database and make it unusable.
If it's possible
Don't do this.
If you really want to try it then still don't.
If you really, really want to try it then find a database you don't care about (the don't care about bit is important!) and log on as a SYSDBA user and:
ALTER TABLE whichever_data_dictionary_table ADD anonymisation_flag VARCHAR2(10);
Then you can test whether the database breaks (and it may not break immediately but at some point later), but if it does then you almost certainly will not get any support from Oracle in fixing it.
Did we say, "Don't do it"... we mean it.
As you already know, you shouldn't do that.
But, nothing prevents you from creating your own table which will contain such an info.
For example:
SQL> CREATE TABLE my_comments
2 (
3 table_name VARCHAR2 (30),
4 column_name VARCHAR2 (30),
5 anonymisation VARCHAR2 (10)
6 );
Table created.
Populate it with some data:
SQL> insert into my_comments (table_name, column_name)
2 select table_name, column_name
3 from user_tab_columns
4 where table_name = 'DEPT';
3 rows created.
Set the anonymisation flag:
SQL> update my_comments set anonymisation = 'F' where column_name = 'DEPTNO';
1 row updated.
When you want to get such an info (along with some more data from user_tab_columns, use (outer) join:
SQL> select u.table_name, u.column_name, u.data_type, u.nullable, m.anonymisation
2 from user_tab_columns u left join my_comments m on m.table_name = u.table_name
3 and m.column_name = u.column_name
4 where u.column_name = 'DEPTNO';
TABLE_NAME COLUMN_NAME DATA_TYPE N ANONYMISATION
---------- --------------- ------------ - ---------------
DEPT DEPTNO NUMBER N F
DSV DEPTNO NUMBER N
DSMV DEPTNO NUMBER Y
EMP DEPTNO NUMBER Y
SQL>
Advantages: you won't break the database & you'll have your additional info.
Drawbacks: you'll have to maintain the table manually.

How to show stored trigger in sql?

I was working on a trigger, now I want to make some changes and see the code, is it possible to see, if so then how? the trigger is working fine, is there any command in plsql to where I can check out the code? I am using sql command line
user_triggers (or all_triggers) have the trigger source code. Similarly user_source (or all_source) have other source code.
General rule though that I follow is to always always always have a file structure where I keep the source. 100% rule that no one in the team is allowed to violate ever. Then I view the act of creating trigger equivalent to "compiling" in traditional programming. In that model, you would have a directory tree for example
<project>/src
<project>/src/plsql
<project>/src/plsql/<folder for each package>/<files>
<project>/src/plsql/<folder for each table>/<triggers>
And then "modifying" is simply changing them here and "compiling" again (compiling will imply running these via sqlplus - or still better creating a shell script.
In this model, you can easily incorporate several available version control tools as well.
GUI would display it prettier, but SQL*Plus can do it as well. Here's an example:
Creating a sample trigger:
SQL> create or replace trigger trg_update_percentage
2 after update or insert on item
3 for each row
4 begin
5 insert into students_percentage (sid, total_per)
6 select sid, total from student_report
7 where sid = :new.sid;
8 end;
9 /
Trigger created.
Fetch its description from USER_TRIGGERS; as the body is stored into the LONG datatype column, set long should be used (otherwise you won't see the complete code).
SQL> set long 4000
SQL> select trigger_name, trigger_type, triggering_event, table_name, trigger_body
2 from user_Triggers where trigger_name = upper('trg_update_percentage');
TRIGGER_NAME TRIGGER_TYPE TRIGGERING_EVENT TABLE_NAME
------------------------- -------------------- -------------------- ----------
TRIGGER_BODY
--------------------------------------------------------------------------------
TRG_UPDATE_PERCENTAGE AFTER EACH ROW INSERT OR UPDATE ITEM
begin
insert into students_percentage (sid, total_per)
select sid, total from student_report
where sid = :new.sid;
end;
SQL>

Need Column name where I know the database and table names

I know the database and table name and need to find a column name. Example as in emp table; I know data 7369 and table name as emp, and I need to get the column name as empno. My table has hundreds of columns and it is getting difficult to search each column name.
You don't have any choice but to search in every column. Please note though that this value could, potentially, appear in multiple columns and/or multiple times in a single column. There's no way to restrict how often it appears across an entire table.
This is the point of a database; everything stored in a column and, most importantly, that column has meaning. If you disassociate the data stored in a column from a meaning then you will have to search everything.
Two steps, not using cursors or complex pl/sql, only SQL Plus.
Produce your search queries:
select select '||
COLUMN_NAME ||
',count(*) from emp where ' ||
column_name || ' = 7369 group by '||
COLUMN_NAME || ';'
from cols
where table_name = 'EMP';
EG:
--------------------------------------------------------------------------------------
select SECOND,count(*) from TESTER where SECOND = 7369 group by SECOND;
(in my env, Second was a column in table TESTER)
Capture the output, clean up the headers and the like, and run it.
It will return every column that matches, along with a count of how many rows matched.

Know if a record is updated within Oracle?

Is there a option to see if existing table/record from a Oracle database is updated?
From a monitoring perspective (not intended to find previous changes), you have several options including but not limited to triggers, streams, and a column with a default value of sysdate. A trigger will allow you to execute a bit of programming logic (stored directly in the trigger or in an external database object) whenever the record changes (insert, update, delete). Streams can be used to track changes by monitoring the redo logs. One of the easiest may be to add a date column with a default value of sysdate.
Are you talking about within a transaction or outside of it?
Within our program we can use things like SQL%ROWCOUNT to see whether our DML succeeded...
SQL> set serveroutput on size unlimited
SQL> begin
2 update emp
3 set job = 'SALESMAN', COMM=10
4 where empno = 8083;
5 dbms_output.put_line('Number of records updated = '||sql%rowcount);
6 end;
7 /
Number of records updated = 1
PL/SQL procedure successfully completed.
SQL>
Alternatively we might test for SQL%FOUND (or SQL%NOTFOUND).
From outside the transaction we can monitor ORA_ROWSCN to see whether a record has changed.
SQL> select ora_rowscn from emp
2 where empno = 8083
3 /
ORA_ROWSCN
----------
83828715
SQL> update emp
2 set comm = 25
3 where empno = 8083
4 /
1 row updated.
SQL> commit
2 /
Commit complete.
SQL> select ora_rowscn from emp
2 where empno = 8083
3 /
ORA_ROWSCN
----------
83828780
SQL>
By default ORA_ROWSCN is set at the block level. If you want to track it at the lower level your need to create the table with the ROWDEPENCIES keyword.
These are ad hoc solutions. If you want to proactive monitoring then you need to implementing some form of logging. Using triggers to write log records is a common solution. If you have Enterprise Edition you should consider using Fine Grained Auditing: Dan Morgan's library has a useful demo of how to use FGA to track changes.
You can see if a table definition has change by querying the last_ddl_time from the user_objects view.
Without using triggers or materialized logs (which would be a total hack) there is no way I know of to see when any particular row in a table has been updated.

Copying fields in Oracle

I am not a programmer, but have a task of automatically copying one field in a table to another field in the same table (it's a long story... :-) ). This should be done on update and insert and I really do not know how to go about it.
I should point out that data is entered to the DB through a user-interface which we do not have the source code for, and therefore we want to do this change on a DB level, using a trigger or likes.
I have tried creating a simple trigger that will copy the values across, but came up with an error message. After Googling the error, I found that I need to create a package which will be used as a variable. Now I am really lost!!!! :-)
I want to also point out that I need a solution that will update this field automatically from now on, but not override any data that already exists in the column.
Could someone show me the easiest and simplest way of doing this entire procedure? I really need a 'Guide for dummies' approach.
Thanks,
David
A simple trigger will be adequate if both fields are on the same table.
Consider:
SQL> CREATE TABLE t (ID NUMBER, source_col VARCHAR2(10), dest_col VARCHAR2(10));
Table created
SQL> CREATE OR REPLACE TRIGGER trg_t
2 BEFORE INSERT OR UPDATE OF source_col ON t
3 FOR EACH ROW
4 BEGIN
5 IF :old.dest_col IS NULL THEN
6 :NEW.dest_col := :NEW.source_col;
7 END IF;
8 END;
9 /
Trigger created
We check if the trigger works for insert then update (the value we inserted will be preserved):
SQL> INSERT INTO t(ID, source_col) VALUES (1, 'a');
1 row inserted
SQL> SELECT * FROM t;
ID SOURCE_COL DEST_COL
---------- ---------- ----------
1 a a
SQL> UPDATE t SET source_col = 'b';
1 row updated
SQL> SELECT * FROM t;
ID SOURCE_COL DEST_COL
---------- ---------- ----------
1 b a
Edit: I updated the trigger to take into account the requirement that the existing data on dest_col is to be preserved.
If you just need the new column to show the exact same data as the old column I think (if you're using Oracle 11g) that you can create a virtual column.
There's an example here.

Resources