SQL Delete Rows with Constraints - sql

I am doing some Exercises and for that I want to delete a Row which is referenced with a Primary/Foreign Key.
Is it possible to delete those Rows without deleting the ones which it has a Relationship with? (like On Delete Cascade)
I also know that I can Disable the constraints, however I want to try deleting without disabling the Constraints.

A row can always be deleted unless its primary key is referenced as a foreign key in a row from another table. In this case, attempting to delete rows will result in an error when the primary/foreign key relationship against data is encountered. The ON DELETE CASCADE option can be used to work around this and delete records from the child table when rows are removed from the parent table.
If you only want to delete the rows that do not have a relationship, then you can exclude the rows that do have a relationship from the delete operation using NOT EXISTS:
DELETE FROM table1 a
WHERE NOT EXISTS (
SELECT FROM table2 b
WHERE b.table1Id = a.id
)

Related

If I delete a record from a table it is deleted at many other places

I am working on a database built by the previous team. I have to delete certain records from a table (Example shown below).
DELETE FROM table WHERE id = 5541
While doing this process, some records from the other tables with the same id is getting deleted. Could someone help how to overcome this problem?
In SQL Server, there is statement called ON DELETE CASCADE which deletes the record from the child table if the record is deleted from the parent table. This can be set using the ALTER STATEMENT as shown below. To remove the cascading, try altering the child table back to default. The default is NO CASCADING.
ALTER TABLE ChildTable
ADD CONSTRAINT FKey
FOREIGN KEY (col1, col2, ... coln)
REFERENCES ParentTable (Pcol1, Pcol2, ... Pcoln)
ON DELETE CASCADE
There is UPDATE CASCADE as well if the data in the child table should be updated when the parent table is updated.
You database most certainly contains foreign key constraints with cascading deletes see docs.
You may be able to remove these foreign keys, but of course, then deleting some rows will leave you with inconsistent data.
Another possibilty is to just remove the cascading deletes. But then of course, you won't be able to delete any rows which are referenced by records from other tables, as SQL server will ensure the consistency of your data.

How to check if foreign key constraint fails when deleting record

I have created a database in SQL Server and front end is PHP - CodeIgniter. In the database I have created multiple foreign keys with other tables. Now when the user tries to delete the record, instead of really deleting I want to flag the record as deleted = 1, this should only be done when there will be no reference records are available in child table. Below are example tables:
Parent_Table
Id INT(PK), Name Varchar, deleted INT
Child_Table
Id INT(PK), FK_Parent_Table_ID INT, address varchar, deleted INT
Above is just example of my tables. Now whenever a user tries to delete a record from the parent table foreign key will check for constraint and then delete the record, here instead of actual deletion I want it flag as deleted = 1.
I have tried using transaction->start and transaction->complete so if foreign key fails the transaction gets aborted but here the problem is if the foreign key not failing then the rollback will occur and in that case the PRIMARY KEY of the record will be changed that should not be done.
So, I want a way to check the foreign key conflict before transaction starts without actual deletion of the record
To implement what you are asking, just check for the existence of a record in the child table e.g.
declare #RecordToDelete int = 123;
-- Delete the record if no child records exist
delete
from Parent_Table
where id = #RecordToDelete
and not exists (select 1 from Child_Table where FK_Parent_Table_ID = #RecordToDelete);
-- Flag the record as deleted if child records exist
update Parent_Table set
Deleted = 1
where id = #RecordToDelete
and exists (select 1 from Child_Table where FK_Parent_Table_ID = #RecordToDelete);
Depending on whether you really need to keep the record, because you could always create your foreign keys with a cascade delete.
With 15+ child tables I would seriously consider just always flagging the record as deleted and never bothering to actually delete those without child records. A few extra records is unlikely to make much difference to your database.
Actually in my experience child tables fall into 2 categories:
Those that can automatically be deleted using a cascade delete
Those that should prevent us from deleting the parent record
If this is the case the checks required should become more manageable.
Also for these situations I recommend encapsulating the delete logic within a stored procedure in order to keep it all in one place, and be easy to modify if the database schemes changes in future.
Note: Personally I would make the Deleted column a bit rather than an int as it more accurately reflects the intention.

Deleting rows that have no referring rows

Lets say I have a table with a fk constraint to the table pk.
I want to delete all rows that has no relation to it.
Is there a way to skip the rows that has a constraint violation and remove all others.
Perhaps a loop with a transaction for each row..
I think you want to delete all rows in pk that have no referring rows. If so:
delete from pk
where not exists (select 1
from fk
where fk.fk = pk.pk
);
Note: You do not want to use not in here, because fk.fk could be NULL.

How can this SQL statement throw the following exception?

how can this statement:
DELETE FROM passage
WHERE passageid NOT IN
(
SELECT passageid from PreEndedPassages_passages
UNION SELECT fromPassageid from severalvisit
UNION SELECT toPassageid from severalvisit
UNION SELECT registerPassageid from stationobjects WHERE registerpassageid IS NOT NULL
UNION SELECT beginPassageid from stationobjects WHERE beginPassageid IS NOT NULL
UNION SELECT endPassageid from stationobjects WHERE endPassageid IS NOT NULL
)
throw this exception?
The DELETE statement conflicted with the FOREIGN KEY constraint "FK_statobj_begpasid". The conflict occurred in database "db.mdf", table "dbo.stationobjects", column 'beginpassageid'.
I have no clue, but it happened. beginPassageId is a foreign key on passageid.
EDIT:
Consider the NOT IN. I want to delete all passages that don't exist in one of its related tables. It usually works, but it happened once.
Thank you.
It means passage is parent table. and stationobjects is child table. You are trying to remove passageid from passage table which is present in stationobjects table as well.
First try to remove those passageid from stationobjects and then you can run this delete statement.
Alternate approach is cascade delete, if your DB supports that.
this kind of occur when you have a foreign key relationship in the two table.
This violates the Refrential Integrity .
so if you delete record from the primary table and record exist in foreign key table,
then you have two options:
1. either set the delete rule to cascade so that when ever you delete primary record the foreign key table record will get automatically deleted.
2.delete record from foreign key table first then from primary key table.
These kind of errors come up when table A foreign key is table B primary key and when you try to delete record in table A that has linking in table B, then deletion will not happen. Try dropping foreign key relation before delete. Same way truncate is used in tables by dropping fk relations and rebuilding them again after the table is reset

How to cascade update 2 tables whose foreign key is not set to cascade?

I got 2 tables. They have a foreign key relation. But the foreign key is not set to update cascade. Now I want to update the table's primary key. SQL Server always prevent me from doing that because of the FK. How could I do it in SQL command? I don't have the right to modify the FK.
Thanks.
Why would you want to do this? It strikes me as potentially hazardous.
Your SQL would need to update the related table first NULLing the links back to the PK table and storing the IDs of the records effected. Then you can update the PK in the PK table. Then go back and update the FKs in the related tables.
Create new rows based on the existing row's attribute values but using the new key value. Do the same for all referencing tables. Then, using the new old key value, delete rows from the referencing tables then the referenced table. Something like:
INSERT INTO Table1 (key_col, attrib_col1)
SELECT 'new_key_value', attrib_col1
FROM Table1
WHERE key_col = 'old_key_value';
INSERT INTO Table2 (key_col, attrib_col2)
SELECT 'new_key_value', attrib_col2
FROM Table2
WHERE key_col = 'old_key_value';
DELETE
FROM Table2
WHERE key_col = 'old_key_value';
DELETE
FROM Table1
WHERE key_col = 'old_key_value';
You should only need to INSERT new rows for the parent table and UPDATE the child rows after the fact...
INSERT INTO ParentTable (PKColumn, attribute1, attribute2)
SELECT 'NewPKValue', attribute1, attribute2
FROM ParentTable
WHERE PKColumn = 'OldPKValue'
;
UPDATE ChildTable
SET FKColumn = 'NewPKValue'
WHERE FKColumn = 'OldPKValue'
;
DELETE
FROM ParentTable
WHERE PKColumn = 'OldPKValue'
;
Now for the gotchas:
1.) The above code wont work if there are any unique indexes defined on non-PK columns in the parent table and you need to use the current records' non-PK data values without modification.
2.) Since you're asking this question, I'm assuming your Parent table is not using an IDENTITY column as the PK.
3.) The code is certainly less than efficient. If your db has to do this infrequently on a few rows, you should be fine. If you need to do this 80 times per second, then I would strongly suggest you talk to the programmer/DBA or vendor, if they're at all available, about updating the FK definition to include ON UPDATE CASCADE.
4.) Make sure that there aren't any triggers on either table that would lead to unintended side effects when you create the new parent records or update the child records.