How to delete a row ONLY in parent table, which is referenced by a Foregin Key from the child table - sql

I want to delete a row/tuple from a parent table, but it is throwing an error message because it has a FOREIGN KEY reference in its child table.
However, in my case I want to delete the record only from the parent table and maintain the data in the child table.
Is it possible to achieve this?
I know the usage of ON DELETE CASCADE, but I want to know if there is a solution for the secenario I described?

It is possible with some agreements in your data. To maintain child table data you'll have to do ON DELETE SET NULL. This will leave data, but set FK to NULL value (in child table). And that is because of data-integrity: while you can keep your data, your FK can not refer to non-existent row of parent table in terms of enforcing FK constraint. Thus, it will be set to NULL by this.
If you want to "save" value of FK - then you definitely should not use FK at all because such behavior violates what FK is. So then just don't use that constraint, but be aware of possible integrity fails.

The point of a foreign key constraint is to prevent orphan records in the child table. So, no, it's not possible to do that, unless you drop the foreign key relationship.
If you rely on 'ON DELETE CASCADE', then deleting the parent record will result in all the corresponding children to be deleted.
If you want to delete the parent, but keep the children, you need to drop the foreign key constraint, or set the constraint to be 'ON DELETE SET NULL'. If you set 'ON DELETE SET NULL', then when you delete the parent record, the child records will remain, but the foreign key column value will be set to NULL.

delete a row ONLY in parent table, which is referenced by a Foregin Key from the child table
If Multiple table has been mapped in one table in that case all foreign key i.e :-
$table->integer('customer_id')->unsigned()->nullable();
$table->foreign('customer_id')->references('id')
->on('customers')->onDelete(`SET NULL`);

Related

Why am I getting an Integrity Constraint (parent key not found) when the parent key exists

I have a parent record in my people table, but when trying to insert a matching record in my employee table, I get a integrity constraint error. Can anyone explain what is wrong?
Ah! Based on your comment:
I've added a pic of the foreign keys, personID is present is both the employee table and customer table and references the people table
it seems that you're mistaken.
Oracle doesn't check whether constraints exist, but whether data (that support those constraints) exist. In other words, first you have to insert a row into a parent table, and then into its child table (whose values "reference" primary key values in the parent table).
The way you posted it, you're inserting into child with no parent.
From the provided images, I can only guess that you are trying to insert a record into "Employee" table with "PersonId" that does not exist in the parent table "People"
If that is not the case, are you able to show us the whole table design including foreign keys?

How to have Delete Cascade on both column that refer the same table?

I have a tables of Items:
ID
NAME
1
GrandParent
2
Parent1
3
Parent2
4
Child1
and a table of ItemRelations:
ParentItemId
ChildItemId
1
2
1
3
2
4
I am trying to have a foreign key with a delete cascade on both ParentItemId and ChildItemId to the itemTable,
When i delete GrandParent, i want to keep the relation between Parent1 and Child1
but SQL is not letting me :
'- Unable to create relationship 'FK_BlockRelations_Child'.
Introducing FOREIGN KEY constraint 'FK_BlockRelations_Child' on table
'BlockRelations' may cause cycles or multiple cascade paths. Specify
ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN
KEY constraints. Could not create constraint or index. See previous
errors.'
The concept of parent/grandparent seems unnecessary because if you have a recursive thing going on and at any point, an item can be a child, grand parent or parent.
In any case, you are trying to give conflicting instructions to the database:
On one hand you are saying that "I am trying to have a foreign key with a delete cascade on both ParentItemId and ChildItemId to the itemTable"
and then in the next sentence "When i delete GrandParent, i want to keep the relation between Parent1 and Child1 but SQL is not letting me"
When you decide to create a cascade delete, it means you are doing 2 things:
Enforcing foreign key constraints - zero tolerance for orphans
Based on those foreign key constraints, you are enforcing an action of deleting everything in Item Relations linked to Items when an item is deleted
Once you enforce (1) then you will not be allowed to add an item into the Item Relations without it first existing in items.
If you then do a cascade delete action based on enforcing #1, then you need to choose which field you use it on. Can't be both unless both are each linked to different tables or one is made to cascade and the other has a no action.
If on the other hand you want to delete grandparent and leave items in Item Relations, what you are saying is that you don't want #1 anymore - no foreign constraint enforcement and a tolerance for orphans.
Once you decide which you want, the right approach should be clear.
You may need to completely abandon foreign key constraint enforcement and consider insert and delete triggers if your delete cascades and foreign key enforcements are conditional and based on the values of the parent.

How to delete records from parent table which is referenced by multiple child tables?

I have a table which is referenced by multiple tables (around 52) and further,few of the child tables have multiple foreign keys also that is referencing other tables too.
I want to delete a record from parent table, I am unable to do so, as I am getting error "The DELETE statement conflicted with the REFERENCE constraint "FK_xxx". The conflict occurred in database "MyDB", table "dbo.A", column 'x'."
I want a generalized T-SQL solution which is irrespective of tables and number of references.
You have to look at the "on delete" keyword which is a part of the foreign key constraint definition.
Basically you have 4 options:
NO ACTION (does nothing)
CASCADE (deletes the child aswell)
SET NULL (sets the reference field to null)
SET DEFAULT (sets the reference field to the default value)
An example would be:
CREATE TABLE parent (
id INT NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE child (
id INT,
parent_id INT,
INDEX par_ind (parent_id),
FOREIGN KEY (parent_id)
REFERENCES parent(id)
ON DELETE CASCADE -- replace CASCADE with your choice
) ENGINE=INNODB;
(for this example and more details look here: http://dev.mysql.com/doc/refman/5.7/en/create-table-foreign-keys.html )
If you now want to modify your constraint, you first have to drop it, and create a new one like for example:
ALTER TABLE child
ADD CONSTRAINT fk_name
FOREIGN KEY (parent_id)
REFERENCES parent(id)
ON DELETE CASCADE; -- replace CASCADE with your choice
I hope this helped. Also to mention it, you should think about maybe not really deleting your parent, and instead creating another boolean column "deleted", which you fill with "yes" if someone clicks the delete. In the "Select"-query you filter then by that "deleted" column.
The advantage is, that you do not lose the history of this entry.
Your problem is this: A FK constraint is designed to prevent you from creating an orphaned child record in any of the 52 tables. I can provide you with the script you seek, but you must realise first that when you try to re-enable the FK constraints the constraints will fail to re-enable because of the orphaned data (which the FK constraints are designed to prevent). For your next step, will have to delete the orphaned data in each of the 52 tables first anyway. It is actually much easier just to redo the constraints with ON DELETE CASCADE, or drop the constraints and forget about referential integrity altogether. You can't have it both ways.

ON DELETE SET NULL on self referencing relationship

I have the table with one primary key and one foreign key referencing the same table primary key.
i.e there are parents and childs in the same table. In sql sever there are three options for the delete rule. But it is only possible to set "NO ACTION" delete rule. I understand that it is not possible to set the "cascade" delete because of cycles and chaining. But why the other options are not allowed? Especially the "SET NULL" one.
Right now I have to do this manually. I have to find the child records and set the foreign key on null. After that I can delete the parent. Why is it not possible to set the rule for it?
Because it cannot perform two actions on the same table together which are:
-delete the parent.
-update the children.
A mutating table is a table that is being modified by an UPDATE, DELETE, or INSERT statement, or a table that might be updated by the effects of a DELETE CASCADE constraint.
you can overcome doing it manually by creating a procedure that would hold the parent key to delete the record and set the children to NULL.
procedure(parent_id) --takes the id as a parameter
update table set null where foreign_key = parent_id;
delete from table where id = parent_id;
end;

ON DELETE CASCADE alternatives and performance (SQL Server)

In my program I store entries in a table and an entry may also have child items.
id uniqueidentifier not null primary key
parent uniqueidentifier null (another id from the same table or null)
... other columns
In this table only top-level entries can have child items, so cycles or recursion are not possible.
If I delete an entry, I want also delete child items. Unfortunately, there is no way to add ON DELETE CASCADE to such table:
Introducing FOREIGN KEY constraint '...' on table '...' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I can, however, just specify an additional condition in my delete statement to do the same:
DELETE FROM mytable WHERE id = #GUID OR parent = #GUID
The problem is that parent column is not indexed. This column also has a lot of duplicate values (NULLs) and as I know, duplicate values are very bad when used with indexes. I would like to know, what is the best solution for this problem
Is there a better solution to remove both child and parent items?
Should I use index on parent column and if yes, what type of index should I use in this case - there are a lot of duplicate values
Not sure, but I suggest that OR-statement in the above solution make primary key index useless and SQL server will just scan the entire table.
PS
I cannot create another table to store child items.