Pseudorecord best practice when trigger fires but value should never change - oracle

Consider the following tables and trigger, is there a need to specify :new.employee_id in the insert statement or is this generally considered best practice. The trigger will only fire on the salary column of the table and the employee_id should not be affected. Is the :new.employee_id syntax just good practice when creating triggers or unnecessary? Could there be a potential issue if this is not added?
Link to Oracle HR SCHEMA employees table
Employees Table HR Schema
CREATE TABLE salary_log (
whodidit VARCHAR2(25), whendidit timestamp,
oldsalary NUMBER,
newsalary NUMBER,
emp_affected NUMBER);
CREATE OR REPLACE TRIGGER saltrig
AFTER INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
BEGIN
INSERT INTO salary_log
VALUES(user,sysdate, :old.salary, :new.salary, :new.employee_id);
END;

If you were to NOT include it:
You would have to alter your trigger code to explicitly name the columns you are supplying values for, and
Your log table would show that someone's salary changed, who did it and what the old and new values are, but you would not know whose salary was changed. The data in that column would be null.
Is the :new.employee_id syntax just good practice when creating triggers or unnecessary?
If you want this value in your log table, then it is required.

Related

Maintain dependency between two tables while executing triggers in oracle

How we can maintain dependency between two tables while executing triggers in oracle??
As we know we can use follows clause if we have single table and multiple triggers based on that table but my concern is that is there any way if we have 2 different tables and there are different triggers based on these table so how can we maintain some proper sequence in this case.
For example:
--Table1:
CREATE TABLE emp(
empId number PRIMARY KEY,
FirstName varchar2(20),
LastName varchar2(20),
Email varchar2(25),
PhoneNo varchar2(25),
Salary number(8)
);
--Table 2:
CREATE TABLE emp_1(
empId number PRIMARY KEY,
FirstName varchar2(20),
LastName varchar2(20),
Email varchar2(25),
PhoneNo varchar2(25),
Salary number(8)
);
Trigger on EMP:
CREATE OR replace TRIGGER TRIGGER_emp
BEFORE INSERT OR AFTER UPDATE ON emp
FOR EACH ROW
BEGIN
dbms_output.put_line ('MY EXECUTE ORDER FOR EMP IS SECOND -EXECUTED');
END;
/
Trigger on EMP1:
CREATE OR replace TRIGGER TRIGGER_emp1
BEFOR INSERT OR AFTER UPDATE ON emp_1
FOR EACH ROW
BEGIN
dbms_output.put_line ('MY EXECUTE ORDER FOR EMP IS FIRST -EXECUTED');
END;
/
Now i want this trigger TRIGGER_emp1 will execute first and then this trigger will execute TRIGGER_emp last. Is it possible to do so in oracle
Please guide me in this.
You seem to be a clone of user who recently posted two questions regarding the same subject. It was said that you can't do that. Triggers "belong" to a single table, which means that
you insert (or update) values in emp table, which then
fires trigger trigger_emp which does something
in your case, it just displays a message (you might, or might not see; that depends on a tool you use)
as nothing happened to table emp1, trigger trigger_emp1 won't fire - why would it?
if you want it to fire, then let the first trigger (trigger_emp) affect rows in emp1 table (insert a row or update existing values)
once you do that, trigger_emp1 will do whatever it does
Maybe, just maybe you should consider creating a stored procedure which contains code that works with rows in both emp and emp1 table. Then, instead of relying on triggers and worry whether they will fire, when will they fire and in which sequence, your main transaction would actually call the procedure which would then do the job (and affect rows in emp and emp1, in any order you want - that's easy to do as you'd just rearrange statements within the procedure).

How to automatically insert foreign key into table after submit in oracle apex?

I have created forms in which the user can enter data. With collections the information is saved and will be inserted in the corresponding tables after the forms are submitted.
Now one column in the table has remained empty and I am not sure how to solve it in APEX.
Namely, the table has a foreign key to another table.
But the ID of this table is generated only after submitting the forms.
Can I solve it, for example, with a trigger that then enters the foreign key into the table after the forms are submitted?
Would it be an after insert trigger like this:
CREATE OR REPLACE TRIGGER INSERT_FK
AFTER INSERT
ON TBL1
FOR EACH ROW
begin
INSERT INTO TBL2
VALUES (:NEW.STUID);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line (TO_CHAR (SQLERRM (-20299)));
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (TO_CHAR (SQLERRM (-20298)));
end;
or is there another better solution for this?
I would not use a trigger for that, but handle this in your application.
You can achieve this by using the RETURNING INTO clause. That allows you to reuse the value of an inserted column in the same transaction.If this is in an anonymous pl/sql block in a page process it would be something like this:
DECLARE
l_id table1.id%TYPE;
BEGIN
INSERT INTO table1(val) VALUES ('Europe')
RETURNING id INTO l_id;
INSERT INTO table2(continent_id, val) VALUES (l_id,'Belgium');
END;
/
In an apex form, you have an option to return the primary key into a page item after insert/update so you can use it in other processes if you use the built-in form processing.
This won't work; you'd insert only the :new.stuid column value into TBL2 which "might" succeed (if other columns in tbl2 aren't NOT NULL), but - all other columns will remain empty.
I guess you should prepare all data while you're still in Apex (i.e. fetch primary key for tbl1 and - at the same time - use it as a foreign key value for tbl2). Otherwise, there's no way to populate that information later because there's no other relation between these two tables (if there were, you wouldn't need the foreign key column, would you?).

trigger performance over different cases

I have a table that collects logs of every check_in. I want to pick 4 columns to later process them. I have placed a trigger on every insert and columns are copied. I am confused over which way to do it. For best PERFORMANCE. Below are some different ways I figured out. Assuming my destination table is indexed.
ALTER trigger GetCheckIn_HA_Transit
on tableXyz
AFTER INSERT
as
declare #cardName nvarchar(max)
declare #checkIn datetime
declare #direction varchar(30)
declare #terminal varchar(30)
select
#direction = str_direction,
#terminal = TERMINAL,
#cardName = card_number,
#checkIn = transit_date
from tableXyz
GO
INSERT INTO logs(direction,terminal,cardName,checkIn)
VALUES
(#direction,#terminal,#cardName,#checkIn)
end
Another way i found was without declaration
ALTER trigger GetCheckIn_HA_Transit
on tableXyz
AFTER INSERT
as
GO
INSERT INTO
logs(direction,terminal,cardName,checkIn)
SELECT(STR_DIRECTION,TERMINAL,card_number,transit_date)FROM tableXyz
And is copying data from one table to another table is better in terms of performance than to copy from one database table to another database table over same server ??
Assuming every second we have an insert that will trigger our Trigger.

Conditional Insert or Update in Oracle

I have one table in oracle where data gets inserted from some third party. I want to populate master tables from that table. So, what will be the best way performance wise using collection.
E.g. Suppose, the table into which data will get populated from third party is 'EMP_TMP'.
Now I want to populate 'EMPLOYEE' master table through procedure which will get populated from EMP_TMP Table.
Here again there is one condition like IF SAME EMPID (this is not primary key) EXISTS then we have to UPDATE FULL TABLE which consists of SAME EMPID ELSE we have INSERT NEW RECORD.
[Note: Here EMPID is VARCHAR2 and EMPNO will be primary key where we will use SEQUENCE]
I think here merge will not perform much better performancewise since we cant use collection in MERGE statement.
Well, if performance is your primary consideration, and you don't like MERGE, then how about this (run as script, single transaction):
delete from EMPLOYEE where emp_id IN (
select emp_id from EMP_TMP);
insert into EMPLOYEE
select * from EMP_TMP;
commit;
Obviously not the "safest" approach (and as written assumes exact same table definitions and you have the rollback), but should be fast (you could also mess with IN vs EXISTS etc). And I couldn't quite understand your post if emp_id or emp_no was the common key in these 2 tables, but use whichever makes sense in your situation.
Create a procedure, you need to be using PL/SQL.
Do an update first then test sql%rowcount.
If it is 0, no updates where done and you have to do an insert instead.
I think that this is fairly efficient.
pseudo code
Update table;
if sql%rowcount = 0 then
//get new sequence number
insert into table;
END IF;
COMMIT;
HTH
Harv

Insert into oracle database

Hi I have a database with loads of columns and I want to insert couple of records for testing, now in order to insert something into that database I'd have to write large query .. is it possible to do something like this
INSERT INTO table (SELECT FROM table WHERE id='5') .. I try to insert the row with ID 5 but I think this will create a problem because it will try to duplicate a record, is it possible to change this ID 5 to let say 1000 then I'd be able to insert data without writing complex query and while doing so avoiding replication of data .. tnx
In PL/SQL you can do something like this:
declare
l_rec table%rowtype;
begin
select * into l_rec from table where id='5';
l_rec.id := 1000;
insert into table values l_rec;
end;
If you have a trigger on the table to handle the primary key from a sequence (:NEW.id = seq_sequence.NEXTVAL) then you should be able to do:
INSERT INTO table
(SELECT columns_needed FROM table WHERE whatever)
This will allow you to add in many rows at one (the number being limited by the WHERE clause). You'll need to select the columns that are required by the table to be not null or not having default values. Beware of any unique constraints as well.
Otherwise you'll be looking at PL/SQL or some other form of script to insert multiple rows.
For each column that has no default value or you want to insert the values other than default, you will need to provide the explicit name and value.
You only can use an implicit list (*) if you want to select all columns and insert them as they are.
Since you are changing the PRIMARY KEY, you need to enumerate.
However, you can create a before update trigger and change the value of the PRIMARY KEY in this trigger.
Note that the trigger cannot reference the table itself, so you will need to provide some other way to get the unique number (like a sequence):
CREATE TRIGGER trg_mytable_bi BEFORE INSERT ON mytable FOR EACH ROW
BEGIN
:NEW.id := s_mytable.nextval;
END;
This way you can use the asterisk but it will always replace the value of the PRIMARY KEY.

Resources