Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How should SQLite foreign keys handle a deleted parent row?

Quick answer

Choose the foreign-key action according to what should happen to dependent child rows: use RESTRICT to prevent deleting a parent while those rows exist, CASCADE to delete them too, or SET NULL to keep them but clear their reference. These actions go on the child table’s REFERENCES constraint. SET NULL requires a child foreign-key column that accepts NULL. Test the selected behavior using disposable sample data. [S1]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I have a parent table and a child table in SQLite. If I delete a parent row, what should happen to the children?

Geez

Decide what the child rows mean before choosing a foreign-key action. SQLite offers three relevant policies: RESTRICT blocks the parent deletion while dependent child rows exist; CASCADE deletes those child rows; SET NULL keeps them but clears their foreign-key values. The action is declared on the child table’s REFERENCES constraint. [S1]

A practical selection guide:

  1. Choose RESTRICT when a child record must remain linked and should not be removed as a side effect.
  2. Choose CASCADE when child records have no purpose without that particular parent and should be removed with it.
  3. Choose SET NULL when child records should remain, but their association with the deleted parent should be removed. The child foreign-key column must allow NULL. [S1]

These policies represent different data-retention decisions; none is automatically the right choice for every relationship.

Follow-up question

Could you show the three choices in small SQLite schemas? I want to compare the actual constraint.

Geez

Here are three alternatives for a hypothetical parent and child relationship. Treat each as a separate disposable example; create the tables in a test database rather than changing important data.

CREATE TABLE parent (
  id INTEGER PRIMARY KEY
);

-- Keep children linked; block deletion while children exist.
CREATE TABLE child_restrict (
  id INTEGER PRIMARY KEY,
  parent_id INTEGER NOT NULL
    REFERENCES parent(id) ON DELETE RESTRICT
);
-- Delete dependent children when their parent is deleted.
CREATE TABLE child_cascade (
  id INTEGER PRIMARY KEY,
  parent_id INTEGER NOT NULL
    REFERENCES parent(id) ON DELETE CASCADE
);
-- Keep children but allow their parent reference to be cleared.
CREATE TABLE child_detachable (
  id INTEGER PRIMARY KEY,
  parent_id INTEGER
    REFERENCES parent(id) ON DELETE SET NULL
);

The action appears on the child-side REFERENCES constraint. In the detachable example, parent_id is not declared NOT NULL, which allows it to hold NULL as required by SET NULL. [S1] These snippets illustrate the constraint choices; they do not establish what policy suits your application.

Follow-up question

How do I decide between keeping a child and setting its reference to NULL, or cascading it away?

Geez

Ask whether the child has meaning on its own after the parent is gone. For example, suppose parent represents a project and child represents a project-specific note. If the note is useful only as part of that project, CASCADE may match the intended relationship. If it should remain available but no longer belong to a project, SET NULL may match instead—provided the reference column can hold NULL. SQLite’s documented actions support those respective outcomes. [S1]

Before choosing, write the intended result in plain language: “When this parent is deleted, I expect these child rows to ___.” Then check any other application requirements about retaining, displaying, or cleaning up those records. The SQLite action alone does not determine your product’s retention policy.

Follow-up question

What should I check before using one of these in my schema?

Geez

Use this short test plan with disposable sample data:

  1. Add one parent and a child that references it.
  2. Confirm which outcome your chosen policy is meant to produce: blocked deletion, deleted child, or retained child with a cleared reference.
  3. Try deleting that parent in the test database and inspect the child table afterward.
  4. For SET NULL, verify the child foreign-key column is permitted to hold NULL; SQLite requires that for this action. [S1]
  5. Repeat with a parent that has no child, and record whether the observed behavior matches your expectation.

The SQLite documentation establishes the three action outcomes and the SET NULL requirement. It does not decide which records your application should preserve, nor does this guide claim the examples have been run against your database. Use your own disposable test data before applying a schema change.

A practical checklist

  • Write down the intended child-row outcome before selecting an action.

  • Put the ON DELETE action on the child table’s REFERENCES constraint.

  • If selecting SET NULL, make sure the child foreign-key column can hold NULL.

  • Test parent deletion with dependent rows using disposable sample data.

  • Inspect the child table afterward and compare it with the intended outcome.

A few more useful answers

Where does SQLite’s ON DELETE action go?

It is specified on the child-table REFERENCES constraint. [S1]

Can I use SET NULL if the child foreign-key column is NOT NULL?

No: SET NULL requires a child column that can hold NULL. [S1]

Does CASCADE keep the child rows?

No. SQLite documents CASCADE as deleting dependent child rows when the parent is deleted. [S1]

Sources

References used for this guide.

  1. [S1] SQLite Foreign Key Support: ON DELETE actions
    sqlite.org · Checked

YOUR QUESTION. YOUR DETAILS.

Let’s work through your situation.

Get a tailored answer or help with your next task. Starts at $1, with a quote before you pay.

Ask your own question
← Back to Geez at Work