I have a parent table and a child table. A parent row stores the foreign key to the child row. If I set the constraint on the foreign key to ON DELETE CASCADE then that will throw an error when I want to delete a parent row where the foreign key points to a child row that is in use by additional parent rows.
This SQL query lists the child rows and how many times they occur. Parent row is the person and the child row is the country.
SELECT country_id, country, COUNT(person.id) FROM nobel_prizes.person JOIN nobel_prizes.countries c on c.id = person.country_id GROUP BY country_id;
Using the results from this, I could delete orphaned rows easily. But is there a more proper method to do this?
2
Answers
I think you have a couple of concepts reversed.
It is customary that the table with the foreign key is called the child. The table referenced by the foreign key is called the parent. In your case, the
person
table is a child of thecountries
table, not the other way around.If you define the foreign key in
person
with theON DELETE CASCADE
option, then deleting a parent row fromcountries
results in deleting all child rows inperson
that reference the deleted row to also be deleted.An orphan row is one that has no parent. It’s a violation of referential integrity.
There is no reverse cascading operation supported by declarative referential integrity (aka foreign keys). That is, if you delete the last row in
person
for a given country, it does not delete that country. It is not a violation of referential integrity for a row incountries
to have zero child rows inperson
depend on it. That’s not an orphan, it’s just a parent with no children (yet).If you want to manually find countries that have zero persons referencing it, use a query like this:
You need to use outer join in this case, because an inner join would match only those rows in
countries
that have one or more matching rows inperson
. To find childless countries, you specifically want those with zero child rows inperson
.I would not expect there to be a need to delete rows from
countries
. There are currently only 195 countries on Earth.A solution which uses AFTER DELETE trigger:
fiddle