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.
Related
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>
I have an oracle client database with 500k client records. Every month i run a batch process to produce some monthly analytical using the client data. But sometimes, the database owner tells me that they have updated the data and i need to run the batch again.
I would like to build a monitoring /notification service that will immediately tell me when a particular client record got updated and what was the update. That way i know if the update can be ignored or not.
I can of course run an hourly sql query that compares each client record with its previous snapshot but is there a better solution?
Does something like Kafka work in this scenario? How exactly?
You can use Continuous Query Notification (previously known as Database Change Notifications).
Read more about it:
DBMS_CQ_NOTIFICATION with examples
Continuous Query Notification for JDBC
#JustinCave also suggests a pretty good option to create simple trigger and enable it only when you really need it, but probably it would be easier just to create materialized view log and check it periodically for new changes. You can get changed rows from it.
Simple example:
SQL> create table t(id int primary key, a int, b int);
Table created.
SQL> create materialized view log on t with primary key, rowid;
Materialized view log created.
SQL> select log_table from user_mview_logs where master='T';
LOG_TABLE
--------------------------------
MLOG$_T
SQL> desc mlog$_t
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
M_ROW$$ VARCHAR2(255)
SNAPTIME$$ DATE
DMLTYPE$$ VARCHAR2(1)
OLD_NEW$$ VARCHAR2(1)
CHANGE_VECTOR$$ RAW(255)
XID$$ NUMBER
SQL> column M_ROW$$ format a20;
SQL> column CHANGE_VECTOR$$ format a10;
SQL> select * from mlog$_t;
no rows selected
SQL> insert into t(id, a, b) values(1,1,1);
1 row created.
SQL> commit;
Commit complete.
SQL> select * from mlog$_t;
ID M_ROW$$ SNAPTIME$$ D O CHANGE_VEC XID$$
---------- -------------------- ------------------- - - ---------- ----------
1 AAASWNAAMAAAAEXAAA 4000-01-01 00:00:00 I N FE 2.8148E+15
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>
I have a table called employees with the following data:
Employee_ID Employee_Salary Employee_HireDate
100 ---- -----
101 ---- -----
Now I want to create a trigger that allows me to fetch the new employee_id and to increment it by one so it can be put in the table. I have found an example like this:
CREATE OR REPLACE TRIGGER employee_b
BEFORE INSERT ON employee
FOR EACH ROW
DECLARE
v_employee_id employee.employee_id%TYPE;
BEGIN
SELECT employee_ID_SEQ.NEXTVAL
INTO v_employee_id
FROM dual;
:NEW.employee_id:=v_employee_id;
END;
But the error that I get is:
ERROR at line 4: PL/SQL: ORA-02289: sequence does not exist
I want to use that trigger before an insert event like:
INSERT INTO employee(employee_salary,employee_hiredate) VALUES (-----,------)
Any help with this?
Thanks
run
create sequence employee_ID_SEQ start with 100 increment by 1;
then compile the trigger and try it. read up on sequences and set an appropriate CACHE etc value (default cache of 20 is probably ok, if you're doing a ton of rapid inserts, you may want more).
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.