I've created a query out of 3 dependent tables:
car parts(id, name, value);
car_model(id, name,price);
part_and_model(car_model_id, car_part_id)
I get my car models from a list of values, and for car_id I use sequence for increment.
I have all the needed fields from my query, but now I want to insert data into car_parts and part_and_model at the same time. I've created two processes on submit to insert (the first for car_parts(fk) and the second for part_and_model). When I run this, I get this error and no data gets inserted into the tables:
ORA-02291: integrity constraint (PRACTICE.FK_CAR_PART_car_part) violated - parent key not found
When I delete the second process, the data is correctly inserted into the car_parts table. Why is this happening? Does the second process execute before first? What else am I missing?
item P8_CAR_MODEL = LOV;
item P8_ID=>sequence: SELECT CP_SEK.NEXTVAL FROM DUAL;
process1:insert into CAR_PARTS(CP_ID,CP_NAME,CP_PRICE) VALUES (:P8_ID, :P8_NAME, :P8_PRICE);
process2: insert into part_and_model(PART_ID, MODEL_ID) values (:P8_ID,:P8_CAR_MODEL);
EDIT:
I managed to insert into car_parts table, but the error still says that the parent cannot be found (even though) it's in the table, so it must be the sequence...
here is my code:
process1:
begin
select PART_SEK.NEXTVAL INTO :P8_ID from dual;
insert into car_parts(id,name,value) VALUES (:P8_ID, :P8_NAME, :P8_PRICE);
end;
process2:
insert into part_and_model(car_model_id, car_part_id) values (:P8_MODEL,:P8_ID);
EDIT2:
when i use PART_SEK.currval instead of p8_id in second process, it works
Once again, thank you all for your time.
Insert rows into both tables in the same process; master table first, details next.
Look at the sequence of the processes. The first process must have a lower sequence e.g 10 and the second must be greater.
Be sure that you in the first process you have to insert into the master table.
Change the processes execution point to processing.
DECLARE
a_id NUMBER;
BEGIN
a_id := your_sequence.nextval;
INSERT INTO car_parts (cp_id, cp_name, cp_price)
VALUES (a_id, :P8_NAME, :P8_PRICE);
INSERT INTO part_and_model (part_id, model_id)
VALUES (a_id, :P8_CAR_MODEL);
END;
By all rights this should work. I do believe your problem really is with the sequence, nothing else I can think of that would cause your error. So please try this and let us know.
Related
Supposing I Have these tables:
CREATE TABLE master
master_id serial,
master_desc character varying
CREATE TABLE details
details_masterrefid int,
details_desc character varying
CONSTRAINT master_detail_fkey(details_masterrefid)
REFERENCES master(master_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION
Then I have a code in C# which basically will insert the header first to the master table and then loop through the details and insert it in the details table.
By doing this, I have to insert to the master table first then commit the transaction, if its successful, get the ID and use it to insert in the details table. Now, the problem is, if something went wrong in the details and the insertion is not successful, I want to rollback the data inserted on the master table. But since its already committed, I cant roll it back. It should be all or nothing. Both the master table and details table.
The only solution I can think of is by allowing the foreign key field in the details to be nullable then if everything is successful, update the foreign key field to its respective value. Any suggestion on how do it better? I dont know if its an efficient solution.
You could use single statement CTE:
WITH ins1 AS (
INSERT INTO master (cols...)
VALUES (..) -- insert into master
RETURNING master_id -- get generated id
)
INSERT INTO details (...)
SELECT master_id, ... -- insert into child table
FROM ins1;
Rextester Demo
Another method is to wrap everything with single transaction:
BEGIN TRAN
INSERT INTO master ...
INSERT INTO child ...
COMMIT;
That way you will get all-or-nothing behaviour.
Is it possible to populate a second table when I insert into the first table?
Insert post to table1 -> table 2 column recieves table1 post's unique id.
What I got so far, am I on the right track?
CONSTRAINT [FK_dbo.Statistics_dbo.News_News_NewsID] FOREIGN KEY ([News_NewsID]) REFERENCES [dbo].[News] ([NewsID])
Lots of ways:
an insert trigger
read SCOPE_IDENTITY() after the first insert, and use it to do a second
use the output clause to do an insert
Examples:
1:
create trigger Foo_Insert on Foo after insert
as
begin
set nocount on
insert Bar(fooid)
select id from inserted
end
go
insert Foo (Name)
values ('abc');
2:
insert Foo (Name)
values ('abc');
declare #id int = SCOPE_IDENTITY();
insert Bar(fooid)
select #id
3:
insert Bar(fooid)
select id from (
insert Foo (Name)
output inserted.id
values ('abc')) x
The only thing I can think of is that you can use a trigger to accomplish this. There is nothing "built in" to SQL Server that would do it. Why not just do it from your .NET code?
Yes it is, it sounds like you want a SQL Trigger, this would allow you to trigger logic based on actions on one table, to perform other actions in the DB. Here's another article on creating Simple SQL Triggers
SQL Server 2008 - Help writing simple INSERT Trigger
A Word of caution, this will do all the logic of updating the new table, outside of any C# code you write, it might sound nice to not have to manage it upfront, but you also lose control over when and if it happens.
So if you need to do something different later, now you have to update your regular code, as well as the trigger code. This type of logic can definitely grow, in large systems, and become a nightmare to maintain. Consider this, the alternative would be to build a method that adds the id to the new table after it inserts into the first table.
While i don't know what you're using to do your inserts assuming it's a SQL Command you can get back the ID on an identity column from the insert using Scope_Identity, found here
How to insert a record and return the newly created ID using a single SqlCommand?
if it's EF or some other ORM tool, they should either automatically update the entity, or have other mechanisms to deliver this data.
To understand an application it would be quite helpful if every database change could be logged somehow. Then you can execute an action on the frontend and see what happens in the database. (I only care about the last 5 minutes, or so, but more would not hurt.) What possibilities exist for that?
I know it is possible to configure the JDBC driver to log the executed statements, but it logs rather more than I want to see (I don't care about queries, for instance) and is mixed wildly into your logfiles. :-/
Another thing I can think of is to create triggers for each table that write data on the changes into a logging-table. Did anyone manage to do that? Especially creating a script that creates those triggers for a given set of tables?
You can find many examples of triggers in Oracle documentation. What you need is after insert, update, delete for each row triggers to populate your log tables. Here's some example from Oracle docs:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#LNPLS020
CREATE TABLE Emp_log (
Emp_id NUMBER,
Log_date DATE,
New_salary NUMBER,
Action VARCHAR2(20));
CREATE OR REPLACE TRIGGER Log_salary_increase_ARUID
AFTER UPDATE OR INSERT OR DELETE ON emp
FOR EACH ROW
BEGIN
-- Can be separated for Inserting then Updating with addl if
-- In this case it may be easier to control and/or add flags to your log tables
-- such as Action = 'INS' or Action = 'UPD' --
If (INSERTING OR UPDATING)
THEN
-- Insert newly created/updated values to your log table --
INSERT INTO Emp_log (Emp_id, Log_date, New_salary, Action)
VALUES (:NEW.Empno, SYSDATE, :NEW.SAL, 'INS_UPD');
ELSE
-- Deleting - insert old or deleted values to your logs --
INSERT INTO Emp_log (Emp_id, Log_date, New_salary, Action)
VALUES (:OLD.Empno, SYSDATE, :OLD.SAL, 'DEL');
END;
/
With the triggers you can just keep the previous data (a history of your data). why you don't simply insert your logs in a log table?
hi i have a problem to insert data in multiple tables. i have define primary key & reference key in tables now i want to insert data in both tables in single query.......how can i do this...........???????
Your question isn't exactly clear on what the particular problem is. I can see three possibilities:
1. You want to insert into two tables wiht a single INSERT statement
2. You want to do two inserts, but without anything else being able to 'get in the middle'
3. You want to insert into one table, then get the primary key to insert into the second table
The answer to 1. is simple:
You can't.
The answer to 2. is simple too:
BEGIN TRANSACTION
INSERT INTO <table1> (a,b,c) VALUES (1,2,3)
INSERT INTO <table2> (a,b,c) VALUES (1,2,3)
COMMIT TRANSACTION
The answer to 3. is has several possibilities. Each depending on exactly what you want to do. Most likely you want to use SCOPE_IDENTITY() but you may also want to look up ##identity and IDENT_CURRENT() to understand the various different options and complexities.
BEGIN TRANSACTION
INSERT INTO <dimension_table> (name)
VALUES ('my new item')
INSERT INTO <fact_table> (item_id, iteam_value)
VALUES (SCOPE_IDENTITY(), 1)
COMMIT TRANSACTION
This is what transactions are meant for. Standard SQL does not permit a single statement inserting into multiple tables at once. The correct way to do it is:
-- begin transaction
insert into table 1 ...
insert into table 2 ...
commit
Does your language support the INSERT ALL construct? If so, that is the best way to do this. In fact it's the only way. I posted an example of this construct in another SO thread (that example syntax comes from Oracle SQL).
The other option is to build a transactional stored procedure which inserts a record into the primary key table followed by a record into the referencing table.
And 1 of your choice to do that is use ORM (like Hibernate, NHibernate) the you make your object and set other relation to it and finally just save the main object , like:
A a;
B b;
C c;
a.set(b);
a.set(c);
DAO.saveOrUpdate(a);
you must notice your DAO.saveOrUpdate(a); line of code just work with hibernate but it insert data into 3 table A, B, C.
I have code snippet in my PL/SQL procedure that does the following:
INSERT INTO payment_operations (id, subscriber, amount, description) VALUES (payment_id, 1234, 5, 'Test');
COMMIT;
SELECT subscriber INTO test_subscriber FROM payment_operations_view WHERE id = payment_id;
After this I get an exception "no_data_found"! However, if I do the same SELECT statement myself after running the procedure, I see the record.
Note that I am selecting from a view, and not directly from the table. Why I cannot see this data right after insertion?
This is a hunch:
Does the payment_options table have a column payment_id?
I ask because in the following statement, within PL/SQL, if payment_id exists as a column, then the column is going to be used not the local PL/SQL variable:
SELECT subscriber
INTO test_subscriber
FROM payment_operations_view
WHERE id = payment_id;
Since it is using the payment_id column, if it exists, and since it was not set in the insert you might be doing where id = null which never evaluates to true.
I use v_ to signify variables. So your snippet would become (with the rest of the procedure changed accordinly):
INSERT INTO payment_operations (id, subscriber, amount, description)
VALUES (v_payment_id, 1234, 5, 'Test');
COMMIT;
SELECT subscriber
INTO v_test_subscriber
FROM payment_operations_view WHERE id = v_payment_id;
Looks like the view you are referring to is a 'materialized' view. If yes, try this code snippet to refresh the view manually before you fetch the data:
...
INSERT INTO payment_operations (id, subscriber, amount, description) VALUES (payment_id, 1234, 5, 'Test');
COMMIT;
DBMS_SNAPSHOT.REFRESH( 'payment_operations_view','c');
SELECT subscriber INTO test_subscriber FROM payment_operations_view WHERE id = payment_id;
DBMS_OUTPUT.PUT_LINE('--> ' || test_subscriber);
...
Hope this helps.
You're inserting into the base table, then selecting from a view. Does the view have any filter conditions? If so, it's possible that the data you've inserted simply doesn't match the view's conditions.
As others have pointed out, it's also possible that the view is a materialized view, in which case it may need to be refreshed.
I have to ask ... why does the logic require selecting out data you've just inserted anyway? Unless you expect something else to have modified the data between the INSERT and SELECT, why not just use the subscriber value that you just inserted instead of querying to get it again?
Explicitly put a commit after the insert statement and check.
To me it appears that select statement is running before the commit actually happens after insert.