postgresql and Delete statement violates foreign key constraint - sql

I have a problem with my delete statement.
I have two tables:
table vehicule_loan(
vehicule TEXT NOT NULL UNIQUE,
);
table vehicule_uid (
id UUID NOT NULL DEFAULT uuid_generate_v4(),
vehicule TEXT NOT NULL REFERENCES vehicule_loan(vehicule) ON DELETE NO ACTION
);
When I delete a vehicule from the table vehicule_loan I want that referencing rows in the table vehicule_uid are kept.
But when I try to delete one I get this error:
ERROR: update or delete on table "vehicule_loan" violates foreign key constraint "vehicule_uid_vehicule_fkey" on table "vehicule_uid"
I think I understand the error:
After I delete a vehicule from the table vehicule_loan, the vehicule in vehicule_uid would point to nothing.
But is there a way to keep the rows in vehicule_uid ?

You should allow NULL values in the foreign key attribute and define the foreign key constraint as ON DELETE SET NULL.
I quote chapter 5.3. Constraints from the PostgreSQL manual:
There are two other options: SET NULL and SET DEFAULT. These cause the
referencing columns to be set to nulls or default values,
respectively, when the referenced row is deleted.
Could look like this:
table vehicule_uid (
id uuid NOT NULL DEFAULT uuid_generate_v4(),
vehicule text REFERENCES vehicule_loan(vehicule) ON DELETE SET NULL
);
With this setting, when you delete a row in vehicule_loan all referencing rows in vehicule_uid remain in database.

Related

Updating primary keys in POSTGRESQL

I have a database from previous project that I want to use in another project, from security reasons I need to update the IDs of one of the table. Problem is that the table is heavily referenced by foreign keys from other tables:
CREATE TABLE "table_table" (
"id" serial NOT NULL PRIMARY KEY,
"created" timestamp with time zone NOT NULL,
);
CREATE TABLE "table_photo" (
"id" serial NOT NULL PRIMARY KEY,
"table_id" integer NOT NULL REFERENCES "table_table" ("id") DEFERRABLE INITIALLY DEFERRED,
);
Now if I change the id on table_table the reference from table_photo won't work.
I will probably use something like this to change the IDs:
UPDATE table_table SET id = id + 15613;
I have read somewhere that I could use ON UPDATE CASCADE constraints to do this but I am not very sure how to use it.
btw: I am using Django ORM.
Get the constraint name with \d "table_photo", which shows:
Foreign-key constraints:
"table_photo_table_id_fkey" FOREIGN KEY (table_id) REFERENCES table_table(id) DEFERRABLE INITIALLY DEFERRED
Then replace it with a constraint that has on update cascade:
ALTER TABLE "table_photo"
DROP CONSTRAINT "table_photo_table_id_fkey",
ADD CONSTRAINT "table_photo_table_id_fkey"
FOREIGN KEY ("table_id")
REFERENCES "table_table"
ON UPDATE CASCADE
DEFERRABLE INITIALLY DEFERRED;
Now when you do your UPDATE, referenced row IDs are automatically updated. Adding an index on "table_photo"."table_id" will help a lot.
This can be slow for big tables though. An alternative if you have large tables is to do it in a couple of stages. For table A with field id that's referenced by table B's field A_id:
Add a new column, new_id, to A, with a UNIQUE constraint. Leave it nullable.
Add a new column, A_new_id to table B, giving it a foreign key constraint to A(new_id).
Populate A.new_id with the new values
Do an
UPDATE B
SET A_new_id = A.new_id
FROM A
WHERE B.A_id = A.id;
to do a joined update, setting the new ID values in B.A_new_id to match.
Drop the column B.A_id and rename B.A_new_id to B.A_id.
Drop the column A.id and rename A.new_id to A.id
Create a PRIMARY KEY constraint on the renamed A.id, USING the index created automatically before.
It's a lot more complicated, especially since for big tables you usually want to do each of these steps in batches.
If this seems too complicated, just do it with a cascading foreign key constraint like above.

The ALTER TABLE statement conflicted with the FOREIGN KEY constraint

Why does add a foreign key to the tblDomare table result in this error?
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK__tblDomare__PersN__5F7E2DAC". The conflict occurred in database "almu0004", table "dbo.tblBana", column 'BanNR'.
Code
CREATE TABLE tblDomare
(PersNR VARCHAR (15) NOT NULL,
fNamn VARCHAR (15) NOT NULL,
eNamn VARCHAR (20) NOT NULL,
Erfarenhet VARCHAR (5),
PRIMARY KEY (PersNR));
INSERT INTO tblDomare (PersNR,fNamn,eNamn,Erfarenhet)
Values (6811034679,'Bengt','Carlberg',10);
INSERT INTO tblDomare (PersNR,fNamn,eNamn,Erfarenhet)
Values (7606091347,'Josefin','Backman',4);
INSERT INTO tblDomare (PersNR,fNamn,eNamn,Erfarenhet)
Values (8508284163,'Johanna','Backman',1);
CREATE TABLE tblBana
(BanNR VARCHAR (15) NOT NULL,
PRIMARY KEY (BanNR));
INSERT INTO tblBana (BanNR)
Values (1);
INSERT INTO tblBana (BanNR)
Values (2);
INSERT INTO tblBana (BanNR)
Values (3);
ALTER TABLE tblDomare
ADD FOREIGN KEY (PersNR)
REFERENCES tblBana(BanNR);
It occurred because you tried to create a foreign key from tblDomare.PersNR to tblBana.BanNR but/and the values in tblDomare.PersNR didn't match with any of the values in tblBana.BanNR. You cannot create a relation which violates referential integrity.
This query was very useful for me. It shows all values that don't have any matches
select FK_column from FK_table
WHERE FK_column NOT IN
(SELECT PK_column from PK_table)
Try this solution:
There is a data item in your table whose associated value doesn't exist in the table you want to use it as a primary key table.
Make your table empty or add the associated value to the second table.
It is possible to create the foreign key using ALTER TABLE tablename WITH NOCHECK ..., which will allow data that violates the foreign key.
"ALTER TABLE tablename WITH NOCHECK ..." option to add the FK -- This solution worked for me.
Remove all existing data from your tables and then make a relation between the tables.
Before You add Foreign key to the table, do the following
Make sure the table must empty or The column data should match.
Make sure it is not null.
If the table contains do not go to design and change, do it manually.
alter table Table 1 add foreign key (Column Name) references Table 2 (Column Name)
alter table Table 1 alter column Column Name attribute not null
I guess, a column value in a foreign key table should match with the column value of the primary key table. If we are trying to create a foreign key constraint between two tables where the value inside one column(going to be the foreign key) is different from the column value of the primary key table then it will throw the message.
So it is always recommended to insert only those values in the Foreign key column which are present in the Primary key table column.
For ex. If the Primary table column has values 1, 2, 3 and in Foreign key column the values inserted are different, then the query would not be executed as it expects the values to be between 1 & 3.
In very simple words your table already has data present in it and the table you are trying to create relationship with does have that Primary key set for the values that are already present.
Either delete all the values of the existing table.
Add all the values of foreign key reference in the new table.
Try DELETE the current datas from tblDomare.PersNR . Because the values in tblDomare.PersNR didn't match with any of the values in tblBana.BanNR.
When you define a Foreign Key in table B referencing the Primary Key of table A it means that when a value is in B, it must be in A. This is to prevent unconsistent modifications to the tables.
In your example, your tables contain:
tblDomare with PRIMARY KEY (PersNR):
PersNR |fNamn |eNamn |Erfarenhet
-----------|----------|-----------|----------
6811034679 |'Bengt' |'Carlberg' |10
7606091347 |'Josefin' |'Backman' |4
8508284163 |'Johanna' |'Backman' |1
---------------------------------------------
tblBana:
BanNR
-----
1
2
3
-----
This statement:
ALTER TABLE tblDomare
ADD FOREIGN KEY (PersNR)
REFERENCES tblBana(BanNR);
says that any line in tblDomare with key PersNR must have a correspondence in table tblBana on key BanNR. Your error is because you have lines inserted in tblDomare with no correspondence in tblBana.
2 solutions to fix your issue:
either add lines in tblBana with BanNR in (6811034679, 7606091347, 8508284163)
or remove all lines in tblDomare that have no correspondence in tblBana (but your table would be empty)
General advice: you should have the Foreign Key constraint before populating the tables. Foreign keys are here to prevent the user of the table from filling the tables with inconsistencies.
i had this error too
as Smutje reffered make sure that you have not a value in foreign key column of your base foreign key table that is not in your reference table i.e(every value in your base foreign key table(value of a column that is foreign key) must also be in your reference table column)
its good to empty your base foreign key table first then set foreign keys
the data you have entered a table(tbldomare) aren't match a data you have assigned primary key table. write between tbldomare and add this word (with nocheck) then execute your code.
for example you entered a table tbldomar this data
INSERT INTO tblDomare (PersNR,fNamn,eNamn,Erfarenhet)
Values (6811034679,'Bengt','Carlberg',10);
and you assigned a foreign key table to accept only 1,2,3.
you have two solutions one is delete the data you have entered a table then execute the code. another is write this word (with nocheck) put it between your table name and add
like this
ALTER TABLE tblDomare with nocheck
ADD FOREIGN KEY (PersNR)
REFERENCES tblBana(BanNR);
Smutje is correct and Chad HedgeCock offered a great layman's example.
Id like to build on Chad's example by offering a way to find/delete those records.
We will use Customer as the Parent and Order as the child. CustomerId is the common field.
select * from Order Child
left join Customer Parent on Child.CustomerId = Parent.CustomerId
where Parent.CustomerId is null
if you are reading this thread... you will get results. These are orphaned children. select * from Order Child
left join Customer Parent on Child.CustomerId = Parent.CustomerId
where Parent.CustomerId is null Note the row count in the bottom right.
Go verify w/ whomever you need to that you are going to delete these rows!
begin tran
delete Order
from Order Child
left join Customer Parent on Child.CustomerId = Parent.CustomerId
where Parent.CustomerId is null
Run the first bit.
Check that row count = what you expected
commit the tran
commit tran
Be careful. Someone's sloppy programming got you into this mess. Make sure you understand the why before you delete the orphans. Maybe the parent needs to be restored.
From our end, this is the scenario:
We have an existing table in the database with records.
Then I introduces a NOT nullable foreign key
After executing the update i got this error.
How did i solve you ask?
SOLUTION: I just removed all the records of the table, then tried to update the database and it was successful.
This happens to me, since I am designing my database, I notice that I change my seed on my main table, now the relational table has no foreign key on the main table.
So I need to truncate both tables, and it now works!
You should see if your tables has any data on the rows. If "yes" then you should truncate the table(s) or else you can make them to have the same number of data at tblDomare.PersNR to tblBana.BanNR and vise-verse.
In my scenario, using EF, upon trying to create this new Foreign Key on existing data, I was wrongly trying to populate the data (make the links) AFTER creating the foreign key.
The fix is to populate your data before creating the foreign key since it checks all of them to see if the links are indeed valid. So it couldn't possibly work if you haven't populated it yet.
I encounter some issue in my project.
In child table, there isn't any record Id equals 1 and 11
I inserted DEAL_ITEM_THIRD_PARTY_PO table which Id equals 1 and 11 then I can create FK
Please first delete data from that table and then run the migration again. You will get success
I had the same problem.
My issue was having nullable: true in column (migration file):
AddColumn("dbo.table", "column", c => c.Int(nullable: true));
Possible Solutions:
Change nullable 'false' to 'true'. (Not Recommended)
Change property type from int to int? (Recommended)
And if required, change this later after adding column > then missing field data in previous records
If you've changed an existing property from nullable to non-nullable:
3) Fill the column data in database records
A foreign key constraint in a child table must have a parent table with a primary key. The primary key must be unique. The foreign key value must match a value in the patent table primary key
When you alter table column from nullable to not nullable column where this column is foreign key, you must :
Firstly, initialize this column with value (because it is foreign
key not nullable).
After that you can alter your table column normally.
Please try below query:
CREATE TABLE tblBana
(BanNR VARCHAR (15) NOT NULL PRIMARY KEY,
);
CREATE TABLE tblDomare
(PersNR VARCHAR (15) NOT NULL PRIMARY KEY,
fNamn VARCHAR (15) NOT NULL,
eNamn VARCHAR (20) NOT NULL,
Erfarenhet VARCHAR (5),
FK_tblBana_Id VARCHAR (15) references tblBana (BanNR)
);
INSERT INTO tblBana (BanNR)
Values (3);
INSERT INTO tblDomare (PersNR,fNamn,eNamn,Erfarenhet,FK_tblBana_Id)
Values (8508284173,'Johanna','Backman',1,3);
or you can use this
SELECT fk_id FROM dbo.tableA
Except
SELECT fk_id From dbo.tableB
and just FYI, in case you do all of your data reference checks and find no bad data...apparently it is not possible to create a foreign key constraint between two tables and fields where those fields are the primary key in both tables! Do not ask me how I know this.

ERROR 1451: Cannot delete or update a parent row: a foreign key constraint fails

CREATE TABLE `categories` (
`idcategories` INT NOT NULL AUTO_INCREMENT ,
`idparent` INT NULL ,
`description` VARCHAR(45) NULL ,
PRIMARY KEY (`idcategories`) );
ALTER TABLE `categories`
ADD CONSTRAINT `FK_idparent`
FOREIGN KEY (`idparent` )
REFERENCES `ilmercatinodelpulcino`.`categories` (`idcategories` )
ON DELETE CASCADE
ON UPDATE CASCADE
, ADD INDEX `FK_idparent` (`idparent` ASC) ;
INSERT INTO `categories` (`idcategories`, `description`)
VALUES (1, 'cat1');
INSERT INTO `categories` (`idcategories`, `idparent`, `description`)
VALUES (2, 1, 'cat1_child');
So this table represents a category, with an ID and a self pointing parent ID.
I have inserted a category cat1 and a subcategory cat1_child with parent id of cat1.
Now, I want to be able to change idcategory of cat1 from 1 to 10 and because I set the foreign key on update CASCADE, I expect that idparent of cat1_child will be set to 10 as well.
But when I do:
UPDATE `categories` SET `idcategories`=10 WHERE `idcategories`='1';
I get an error:
ERROR 1451: Cannot delete or update a parent row: a foreign key
constraint fails (categories, CONSTRAINT FK_idparent FOREIGN KEY
(idparent) REFERENCES categories (idcategories) ON DELETE
CASCADE ON UPDATE CASCADE) SQL Statement: UPDATE categories SET
idcategories=10 WHERE idcategories='1'
The delete instead work as expected and deleting cat1, cat1_child will be deleted as well.
Where is the error?
Than you.
I believe the answer is in the documentation (scroll down to the bottom):
Deviation from SQL standards: If ON UPDATE CASCADE or ON UPDATE SET
NULL recurses to update the same table it has previously updated
during the cascade, it acts like RESTRICT. This means that you cannot
use self-referential ON UPDATE CASCADE or ON UPDATE SET NULL
operations. This is to prevent infinite loops resulting from cascaded
updates. A self-referential ON DELETE SET NULL, on the other hand, is
possible, as is a self-referential ON DELETE CASCADE. Cascading
operations may not be nested more than 15 levels deep.
Demo: http://www.sqlfiddle.com/#!2/e29db/1
I faced the same issue then i disabled the foreign key check using below query and then i was able to delete the row
SET FOREIGN_KEY_CHECKS=0;
You can also enable the foreign key check using below query
SET FOREIGN_KEY_CHECKS=1;

Does a foreign key constraint automatically disallow nulls?

In my Activities table I have a StaffId field. This is a FK of the Staff table (that holds StaffId). On inserting data into the Activities table - if the StaffId is null it throws a FK constraint error!? I have ticked the 'Alllow Nulls' box in SSMS so why is this not the case?
Note, this record is being inserted through the DbCommand.ExecuteNonQuery method.
Also note: I have just ran an Insert statement using SSMS to insert NULL values, and it worked. May be this is a more C# specific question!?
No, look at this http://msdn.microsoft.com/en-us/library/ms175464.aspx
A FOREIGN KEY constraint does not have to be linked only to a PRIMARY
KEY constraint in another table; it can also be defined to reference
the columns of a UNIQUE constraint in another table. A FOREIGN KEY
constraint can contain null values; however, if any column of a
composite FOREIGN KEY constraint contains null values, verification of
all values that make up the FOREIGN KEY constraint is skipped. To make
sure that all values of a composite FOREIGN KEY constraint are
verified, specify NOT NULL on all the participating columns.
you can see another example in MySql, look at the following link http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html
You can see that it is possible to SET NULL
SET NULL: Delete or update the row from the parent table and set the
foreign key column or columns in the child table to NULL. This is
valid only if the foreign key columns do not have the NOT NULL
qualifier specified. Both ON DELETE SET NULL and ON UPDATE SET NULL
clauses are supported.
If you specify a SET NULL action, make sure that you have not declared
the columns in the child table as NOT NULL.
It is possible to do on the DB as #Martin demonstrated. The problem is on your front end. DbCommand has issues dealing with NULLs, that's one of the reasons they created Linq To Sql.
I suggest you try something like this:
if(parameter_is_not_null)
db.AddInParameter(dbCommand, "staffId", DbType.String, staffId.Text);
else
db.AddInParameter(dbCommand, "staffId", DbType.String, DBNull.Value);

What is the best way to empty a self-referential MySQL table?

I have a self-referential MySQL table with a recursive parent_id:
CREATE TABLE `recursive` (
`id` int(11) NOT NULL auto_increment,
`parent_id` int(11) default NULL,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `data_categorysource_parent_id` (`parent_id`),
CONSTRAINT `parent_id_refs_id_627b4293`
FOREIGN KEY (`parent_id`) REFERENCES `data_categorysource` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
During testing, I want to empty it but TRUNCATE fails:
TRUNCATE `recursive`
/* SQL Error: Cannot delete or update a parent row: a foreign key
constraint fails...
I currently have to manually delete all records, starting at the bottom of the tree working upwards. This gets onerous even with small trees.
Is there an easy way around this? I can't DROP the table and re-create it easily as other tables reference it (I have already truncated those so there should be no data integrity issues there).
Why not:
UPDATE 'recursive' SET 'parent_id' = NULL WHERE 'parent_id' IS NOT NULL;
DELETE FROM 'recursive';
?
If you just want to empty the whole thing for testing purposes use:
SET FOREIGN_KEY_CHECKS = 0;
// Execute Query
SET FOREIGN_KEY_CHECKS = 1;
This totally bypasses any foreign key checks.
Well, you could add an ON DELETE CASCADE to the FOREIGN KEY definition... at least temporarily. That would allow you to truncate the table by removing the referenced rows first.
There are other ON DELETE types as well; the default is ON DELETE NO ACTION.
Or just remove the (recursive) foreign key constraint, then truncate the table, then re-add the contraint.
Repeatedly select the rows that do not appear as parents and delete them, until the table is empty. (Assuming there are no cycles...)
delete from table_1 where date(table_1_TIME) < (select T.t_Date from (select max(date(table_1_TIME)) as t_Date from table_1 ) as T)