Recent chats
ASKGEEZ Q&A GUIDETechnology & devices

How can a SQLite schema represent an optional relationship?

Quick answer

Represent an optional parent relationship with a child-table foreign-key column that permits NULL, such as project_id INTEGER REFERENCES project(id). In SQLite, NULL satisfies the foreign key; a non-NULL value must match a parent key. [S1] Choose a delete action based on what should happen when that parent is deleted: SET NULL preserves the child without the relationship, while other actions have different effects. Check that foreign-key enforcement is enabled in your application; the schema alone does not establish that it is. [S1]

LET’S WORK THROUGH IT

The question, the details, the next step.

Question

I have a task table and an optional relationship to a project. Some tasks belong to a project, but others do not. How should I model that?

Geez

Put the foreign key on the table whose rows may or may not point to a parent—in this example, task. Make that column nullable, rather than requiring every task to have a project:

CREATE TABLE project (
  id INTEGER PRIMARY KEY
);

CREATE TABLE task (
  id INTEGER PRIMARY KEY,
  project_id INTEGER REFERENCES project(id)
);

Here, a task with project_id set to NULL has no project; a non-NULL value must match a project.id. SQLite treats a NULL child key as satisfying the foreign key. [S1] This represents an optional link from a task to a project. It does not, by itself, say that every project must have a task, or limit how many tasks can refer to one project.

Follow-up question

What if I want to delete a project but keep its tasks?

Geez

If keeping the tasks and removing their project association is the intended result, add ON DELETE SET NULL to the foreign key:

project_id INTEGER REFERENCES project(id) ON DELETE SET NULL

When a referenced project is deleted, SQLite sets the matching child key to NULL. [S1] That result must still satisfy the column’s other constraints and foreign-key rules, so do not combine this choice with a rule that forbids NULL in project_id. [S1] This action changes the relationship, not the task’s other data. If instead you want deleting a project to remove its tasks, that is a different design choice; do not select SET NULL for that outcome.

Follow-up question

How do I decide whether the relationship should be optional, and which delete action fits?

Geez

Start with the rule for a single task: can it validly exist without a project? If yes, allow NULL; if no, the relationship should be required and the column should not permit NULL. Then decide what a project deletion means for tasks. SQLite documents NO ACTION as the default when no action is specified, and lists RESTRICT, SET NULL, SET DEFAULT, and CASCADE as other actions. [S1] Choose based on the intended outcome, not convenience: SET NULL means keep the child without its parent. SET DEFAULT depends on the resulting default satisfying the schema’s constraints and foreign-key rules. [S1]

A useful decision note for the example is:

Can a task exist without a project? Yes.
Can project_id be NULL? Yes.
When a project is deleted, should tasks remain unassigned? Yes: choose ON DELETE SET NULL.

If your answers differ, change the column rule or delete action accordingly.

Follow-up question

What should I check before relying on this schema?

Geez

Check both the design and the application behavior. A declaration in the schema describes the relationship, but it does not establish that foreign-key enforcement is enabled for every application or connection. [S1] Confirm that enforcement is enabled in the environment that uses the database, then check that NULL and matching parent values are accepted and that a missing parent is rejected. For SET NULL, test deleting a referenced project and confirm the task remains with a NULL project_id. These are verification steps for your own database, not results guaranteed by the example.

A practical checklist

  • Decide whether a child row can validly exist without its parent.

  • Use a nullable foreign-key column only when that absent relationship is allowed.

  • Choose the parent-deletion outcome deliberately; use SET NULL when children should remain unassigned.

  • Check that the result of the delete action satisfies the column’s other constraints.

  • Verify foreign-key enforcement and test NULL, matching-parent, missing-parent, and deletion cases in the application environment.

A few more useful answers

Does a NULL foreign key refer to a parent row?

No. In SQLite, a NULL child key satisfies the foreign key without requiring a matching parent; a non-NULL child key must match a parent key. [S1]

Does `ON DELETE SET NULL` delete the child row?

No. It sets the child key to NULL when a referenced parent is deleted, so the child remains without that relationship. The resulting value must satisfy the schema’s other constraints and foreign-key rules. [S1]

Does declaring a foreign key prove that enforcement is enabled?

No. The cited SQLite documentation does not establish that enforcement is enabled in every application or connection. [S1] Check the environment that uses your database.

Sources

References used for this guide.

  1. [S1] SQLite Foreign Key Support
    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