1

I have a table design where "notes" for various entities are handled using a relational table. For example, the following tables exist

'notes' table having fields id and note
'knifes' table having as only field an id
'knife_notes' table having knife_id and note_id, being foreign keys to 'id' in knifes table 
and notes 'id' in notes table respectively.

Update: the note_id field in the knife_notes tables is unique, so that each note can only be related to one particular knife.

When adding a note, i.e. a child, for a knife (parent), a note record is created and a record in table knife_notes is create too, thereby relating a notes id and a knifes id.

The two foreign keys are having 'On Delete Cascade'. However, when a knife is deleted, only the records in knife_notes are 'cascade' deleted, not the records in the notes table.

Do I need a second query to delete the notes records when deleting a knife, or is there a better way?

1 Answer 1

1

What you did was create an n-to-m relationship between knives and notes. Are you sure that is what you need?

Because, the way your datamodel is set up now, it is actually desirable that notes aren't deleted. The current model allows (amongst others):

A. A knife that has 1 note

B. A specific knife that has more than 1 note (2 rows in knife_notes that point to the same knife and to different notes)

C. A specific note that is related to multiple knives

Because of scenario C the database can't just cascade from the knive_notes table to the notes table: there might be other tables that are dependent on a specific note.

To make it visual, think of this scenario in the knive_notes table:

id   knife_id    note_id
--------------------------------------
1    11          101
2    11          102
3    12          103
4    13          103

From a database point of view this is perfectly legal; note 103 is used for both knive 12 and 13. Now if you were to delete knive 12, the database can't simply remove note 103, because it could still be used by other knives (and in fact it is).

There are 2 sollutions I can think of: 1. simplify your datamodel 2. create a trigger or rule in PostgreSQL

Expanding on the options:

  1. datamodel:

Why don't you create a datamodel that only has

  • Knive
  • Note (with a foreign key to knive)

This way a knive can have multiple notes, but a note always is related to a knive. This will not work, though, if a note is used multiple times or in multiple roles (ie. if you also have a table "guns" that also needs notes or if a specific note is used by multiple rows in the knive table ("the color of this knive is red")

  1. triggers or rules

With rules you can rewrite your SQL query. With triggers you can execute a function just before or after an operation on a table. Look up triggers & rewrite rules.

Myself, I'm most used to working with triggers. I would basically create an on-delete trigger that starts a trigger function. In that function I would check if the note isn't used anywhere else and if that is the case execute a delete on the note.

CREATE FUNCTION try_to_delete_note() RETURNS trigger AS ##
DECLARE
  usage_found int;
BEGIN
    -- Check that note is not used anywhere else
  usage_found = (select count(*) from knive_notes where note_id = OLD.note_id)
  IF (usage_found = 0) THEN
    DELETE from note where id = OLD.note_id    
  END IF;    

  RETURN NULL; -- result is ignored since this is an after trigger
END;
## LANGUAGE plpgsql;

CREATE TRIGGER knife_notes_deleted_trigger
AFTER DELETE ON knife_notes
FOR EACH ROW
EXECUTE PROCEDURE try_to_delete_note();

Also see this page in postgresql docs with trigger examples.

Sign up to request clarification or add additional context in comments.

3 Comments

Great response. In fact, your response made me realized that my model is flaw. Model should be that each knife can have many notes, but one note can only be related to one knife. I guess by making note_id in the knife_notes table would enforce that. Would that change how children are deleted?
Also, I do prefer a 'notes' table with no foreign keys and use relation tables, like the knife_notes table to reference the notes. Alternative is to have separate notes tables for each entity that can have notes, and I find that messier.
If you use notes for different entities, then this is a reasonable model. It just isn't able to cascade a delete, so you would have to use the triggers. I'll append my answer to show why a little better.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.