Using the trigger noted below, I am tracking changes in a producution table in an audit, or change-log table. My problem is that the field names in the tracking table are different from the ones in table1. The values are the same, but the names of the columns are different.
The question is then, how must the syntax change in the trigger to take the value of one field name and insert it into a field of a different name in the tracking table?
Thank you for any and all help or suggestions.
{
CREATE OR REPLACE TRIGGER track_change_trg
AFTER INSERT OR UPDATE OR DELETE
ON table1
FOR EACH ROW
BEGIN
IF INSERTING THEN
INSERT INTO tracking table VALUES
(:new.pname, :new.p_id, :new.p_type, :new.t1name,
'INSERTED', SYSDATE);
ESLIF UPDATING THEN
INSERT INTO tracking table VALUES
(:new.pname, :new.p_id, :new.p_type, :new.t1name,
'UPDATED', SYSDATE);
ELSIF DELETING THEN
INSERT INTO tracking table VALUES
(:old.pname, :old.p_id, :old.p_type, :old.t1name,
'DELETED', SYSDATE);
END IF;
END;
/
}
It makes no difference if the column names are different in the main and audit table. I'm not sure why you think that's a problem - showing any error might have helped clarifying your issue, along with the table definitions. The only error I can immediately see being thrown - assuming the space in tracking table is a mistake in transcription - is if the column order doesn't match and you're putting the wrong type or size of data in a column. Hard to guess what you're seeing though.
You've omitted the the optional column section in the insert statement that would normally list the column names. Without an explicit list of the column names, the values will be assigned based on the order of the columns in the target table, as shown in user_tab_columns.column_id or with describe. It would be better to list the columns to avoid ambiguity. and so you don't have problems if the table definition changes (e.g. a column is added, so you not don't have enough values) or the column order is different in another environment (which arguably shouldn't happen under decent source control). It's easier to spot trivial mistakes too.
Anyway, just list the column names from the table you're inserting into:
INSERT INTO tracking_table (x_name, x_id, x_type, x_t1name, x_action, x_when)
VALUES (:new.pname, :new.p_id, :new.p_type, :new.t1name, 'INSERTED', SYSDATE);
... replacing x_name etc. with the actual column names from tracking_table.
Related
I have an Interface which's created with Oracle Forms. It has a base table block in which there's a field (namely col3"has the same name with the table's column that's derived from").
Form has two other fields col1 and col2 as of numeric type, and those fields are also members of the same table having col3 column mentioned above.
I converted col3 to a virtual column as the sum of the columns col1 and col2 in the table's definition( col3 number generated always as (nvl(col1,0)+nvl(col2,0)) virtual )
When I try to commit the changes in the base table it hurls the error message
ORA-54013: INSERT operation disallowed on virtual columns
I know applying a DML to a virtual column has no sense, but even I changed the col3 field's
Query Only property from No to Yes
Update Allowed property from Yes to No
Insert Allowed property from Yes to No
I get the same error message. I don't want to write explicit DML statements, since the form has lots of other fields, and they should also be listed in those statements.
Do you have any idea how I can overcome this problem without giving up base table block structure ? ( I'm using the version Fusion Middleware 11g )
As everything you do with that column is query, how about setting it to be a non-database column? It would require writing a POST-QUERY trigger, though - otherwise you wouldn't see its value after executing a query.
:block.col3 := :block.col1 + :block.col2;
Put the same code into WHEN-VALIDATE-ITEM triggers on both :block.col1 and :block.col2 items, so that you'd calculate the result when inserting/updating values.
Alternatively, create a procedure (within the form), put the above code into it, and then call the procedure from those triggers - for a long term, that's probably a better choice as you'd have to maintain code changes only in the procedure.
I'm using Oracle 12.
When you define insert statement there is option not to state column list
If you omit the column list altogether, then the values_clause or query must specify values for all columns in the table.
Also it's describe in Ask TOM when suggesting a best performance solution for bulk:
insert into insert_into_table values ( data(i) );
My question, is not stating columns really produce a better or at least equal performance than stating column in statement as
insert table A (col1, col2, col3) values (?, ?, ?);
From my experience there is no gain in omitting column names - also it's a bad practice to do so, since if column order changes (sometimes people do that, for clarity, but they really don't need to) and their definition allows to insert the data, you will get wrong data in wrong columns.
As a rule of thumb it's not worth the trouble. Always specify column list that you're putting values into. Database has to check that anyways.
Related: SQL INSERT performance omitting field names?
Best practice is, that you ALWAYS define the columns in insert statements, NOT for the performance sake(there is no difference), but for situation like this:
You create table test1 with columns col1, col2;
You insert data in that table in your procedures/etc, without naming the columns;
You add new columns, col3, col4;
The current logic will fail with insert, errors will be raised.
So, to avoid the failure, always name the columns, then your code doesn't brake,when you modify the table structure.
I am using an AFTER INSERT row trigger in Oracle 11g to copy specific columns from one table to another on insert. I have the trigger and insert working ok. The problem I have is that I need to insert the new data from one column to a different column when copying it.
The trigger info reads:
BEGIN
insert into BALES_STORAGE
(CROP,
CUTTING,
DESTINATION,
BALES_MOVED,
DATE_MOVED,
PASTURE,
TARGET_LB_PER_DAY)
values
(:new.CROP,
:new.CUTTING,
:new.MOVING_LOCATION,
:new.BALES_MOVED,
:new.DATE_MOVED,
:new.PASTURE,
:new.TARGET_LB_PER_DAY);
END;
The first table is called "BALES_HARVESTED" and the 2nd table the trigger inserts the selected columns into is called "BALES_STORAGE". I need to insert the :new.MOVING_LOCATION data into the column called DESTINATION on the second table.
So my question is: when using an after insert row trigger, how to I change the column that the data is inserted into?
Thanks for any help.
Matthew
Your trigger code worked just fine for me. Not sure what the problem is. The 3rd column in your INSERT statement does the column mapping correctly.
http://sqlfiddle.com/#!4/2d2fd5/1/1
Maybe you have different structures or foreign key constraints. Could you elaborate on what error you get? Does it produce an ORA- error? or does it simply not produce the desired result, but no error?
Can any one tell me the Difference Between Insert and Append statement in SQL Loader?consider the below example :
Here is my control file
load_1.ctl
load data
infile 'load_1.dat' "str '\r\n'"
insert*/+append/* into table sql_loader_1
(
load_time sysdate,
field_2 position( 1:10),
field_1 position(11:20)
)
Here is my data file
load_1.dat
0123456789abcdefghij
**********##########
foo bar
here comes a very long line
and the next is
short
The documentation is fairly clear; use INSERT when you're loading into an empty table, and APPEND when adding rows to a table that (might) contains data (that you want to keep).
APPEND will still work if your table is empty. INSERT might be safer if you're expecting the table to be empty, as it will error if that isn't true, possibly avoiding unexpected results (particularly if you don't notice and don't get other errors like unique index constraint violations) and/or a post-load data cleanse.
The difference are in two points clear:
append will only add the record if at the end of statement
insert will insert anywhere you want i.e if your table have 10 column you can insert in 5 column only but in append you can't.
in append both your data and the table should have same columns means insert data in row level rather than in column level
and it's also true you cannot use insert if your table have data if it's empty then only you can do use insert.
hope it helps
I have some large tables (millions of rows). I constantly receive files containing new rows to add in to those tables - up to 50 million rows per day. Around 0.1% of the rows I receive are duplicates of rows I have already loaded (or are duplicates within the files). I would like to prevent those rows being loaded in to the table.
I currently use SQLLoader in order to have sufficient performance to cope with my large data volume. If I take the obvious step and add a unique index on the columns which goven whether or not a row is a duplicate, SQLLoader will start to fail the entire file which contains the duplicate row - whereas I only want to prevent the duplicate row itself being loaded.
I know that in SQL Server and Sybase I can create a unique index with the 'Ignore Duplicates' property and that if I then use BCP the duplicate rows (as defined by that index) will simply not be loaded.
Is there some way to achieve the same effect in Oracle?
I do not want to remove the duplicate rows once they have been loaded - it's important to me that they should never be loaded in the first place.
What do you mean by "duplicate"? If you have a column which defines a unique row you should setup a unique constraint against that column. One typically creates a unique index on this column, which will automatically setup the constraint.
EDIT:
Yes, as commented below you should setup a "bad" file for SQL*Loader to capture invalid rows. But I think that establishing the unique index is probably a good idea from a data-integrity standpoint.
Use Oracle MERGE statement. Some explanations here.
You dint inform about what release of Oracle you have. Have a look at there for merge command.
Basically like this
---- Loop through all the rows from a record temp_emp_rec
MERGE INTO hr.employees e
USING temp_emp_rec t
ON (e.emp_ID = t.emp_ID)
WHEN MATCHED THEN
--- _You can update_
UPDATE
SET first_name = t.first_name,
last_name = t.last_name
--- _Insert into the table_
WHEN NOT MATCHED THEN
INSERT (emp_id, first_name, last_name)
VALUES (t.emp_id, t.first_name, t.last_name);
I would use integrity constraints defined on the appropriate table columns.
This page from the Oracle concepts manual gives an overview, if you also scroll down you will see what types of constraints are available.
use below option, if you will get this much error 9999999 after that your sqlldr will terminate.
OPTIONS (ERRORS=9999999, DIRECT=FALSE )
LOAD DATA
you will get duplicate records in bad file.
sqlldr user/password#schema CONTROL=file.ctl, LOG=file.log, BAD=file.bad