Reputation: 111
I am soft-deleting data using a binary check is_deleted
field in db tables.I have country(parent) and city(child) tables in db.The problem is if user try to soft-delete a country which has associated data in city table,it should not allow user to delete it
fields in country table: id,name,is_deleted
fields in city table: id,name,is,is_deleted,country_id
(foreign key)
Creating sample data:
insert into country(id,name,is_deleted) values(1,'United Stated', false)
insert into city(id,name,is_deleted,country_id) values(1,'Washington',false,1)
trying to soft-delete from country which has associated data in child
update country set is_deleted = true where id = 1
On soft-deletion it should give me error or some message
Upvotes: 1
Views: 248
Reputation: 14861
@LaurenzAlbe provides a pretty cool solution, but maybe a little too awkward. Perhaps a trigger would be a little less so (though I generally dislike triggers). Either way a point you need to consider: What happens when I insert a city for a country that has been flagged as deleted, and the new city is not flagged as deleted? See fiddle.
create or replace
function validate_all_cities_deleted()
returns trigger
language plpgsql
as $$
declare nl constant varchar(1) := chr(10);
begin
if exists
( select null
from city
where country_id = new.id
and not is_deleted
)
then
raise exception 'Business Rule Violation:% Cannot "delete" % while it has at least 1 non-deleted city.',nl,new.name
using
hint = format ('Check all cities with with country_id = %s (%s), set their is_deleted = True, then retry',new.id,new.name)
;
end if;
return new;
end;
$$;
create trigger remove_country_city_bur
before update of is_deleted
on country
for each row
execute function validate_all_cities_deleted();
Upvotes: 0
Reputation: 246268
The only way I can think of is slightly awkward:
/* add a column that mirrors "is_deleted" from "cuntry" */
ALTER TABLE city ADD country_is_deleted boolean DEFAULT FALSE NOT NULL;
/* this will be the target of the foreign key, no other purpose */
ALTER TABLE country ADD UNIQUE (id, is_deleted);
/* make sure "country_id" and "country_is_deleted" match the values
in "country", and that every soft delete in "country" is replicated */
ALTER TABLE city ADD FOREIGN KEY (country_id, country_is_deleted)
REFERENCES country (id, is_deleted)
ON UPDATE CASCADE;
/* make sure no country can be deleted when the city is not deleted */
ALTER TABLE city ADD CHECK (country_is_deleted IS FALSE OR is_deleted IS TRUE);
Upvotes: 1