Transaction Management and Rollback
User registration, tag or category management, and reference-data linking are examples of workflows where an existing record can be reused or a missing record can be created.
A Duplicate That Need Not Crash
Suppose an application receives a username that may already be stored. A normal insertion that violates a constraint raises an error and rejects the operation. That behavior protects the database from invalid data, but it may not match the application's goal. Sometimes the correct response is to reuse the existing record and continue. SQLite's INSERT OR IGNORE directive supports this behavior: if the attempted insertion would violate a constraint, the insertion is silently skipped and the program continues.
INSERT OR IGNORE has two possible outcomes: a valid new row is inserted, or an insertion that would violate a constraint is quietly skipped.
Tracing the Two Outcomes
The important distinction is between the insertion attempt and the final table state. INSERT OR IGNORE does not update an existing row when a conflict occurs. It leaves the attempted row out of the table. If no constraint would be violated, the new row is added normally.
What do you think happens?
A table already contains the unique username sam. What should happen when INSERT OR IGNORE attempts to add sam again?
Reveal answer
The attempted insertion is skipped and the program continues
The duplicate violates the uniqueness constraint, so INSERT OR IGNORE silently ignores that insertion. The existing row remains.
Why Uniqueness Matters
The duplicate-handling behavior depends on a constraint that can identify a conflict. A UNIQUE constraint restricts duplicate values in one or more columns. If a username column is UNIQUE, two rows cannot have the same username, so attempting to insert an existing username creates a constraint violation that INSERT OR IGNORE can skip.
| Column situation | Attempted duplicate | Result with INSERT OR IGNORE |
|---|---|---|
| A UNIQUE constraint is present | The value violates the constraint | The insertion is skipped |
| No UNIQUE constraint is present | The value is allowed to repeat | The row is inserted, assuming no other constraint is violated |
A duplicate value is skipped only when it conflicts with a constraint.
Finding the Record ID
Skipping a duplicate is useful, but an application often needs the record's primary key afterward. The practical pattern is a two-step sequence: first attempt the insertion with INSERT OR IGNORE, then run SELECT to retrieve the primary key for the unique value. If the value was new, SELECT finds the row just inserted. If the value already existed, SELECT finds that existing row.
INSERT OR IGNORE INTO users (username)
VALUES ('sam');
SELECT user_id
FROM users
WHERE username = 'sam';- 1The INSERT OR IGNORE statement attempts to add sam.
- 2If sam is already present under a UNIQUE constraint, the insertion is skipped without an error.
- 3The SELECT then searches for sam and retrieves its
user_id. - 4The unique value makes this lookup reliable because it maps to exactly one row.
- The first statement attempts to ensure that sam exists.
- The second statement retrieves the primary key associated with sam.
The SELECT returns the user_id for sam, whether the row was newly inserted or was already present.users contains: sam
The existing sam row is present.
INSERT OR IGNORE attempts sam again
The table still contains one sam row; the duplicate insertion is ignored.
The SELECT follow-up is reliable only when the value used in the search is unique. If several rows could share that value, the SELECT would not identify one specific record. This is why the UNIQUE constraint is central to the pattern rather than an optional detail.
Choosing the Pattern Carefully
Use this pattern when the application needs to ensure that a record exists and then use its primary key. User registration, tag or category management, and reference-data linking are examples of workflows where an existing record can be reused or a missing record can be created.
Do not choose this pattern when the application must know whether the insertion actually occurred. INSERT OR IGNORE intentionally hides the constraint-violation error by skipping the insertion. If later logic depends on distinguishing a newly created row from an ignored duplicate, a different approach is needed, such as checking existence before insertion or using a more complex conditional statement.
Common mistake Assuming every repeated value will be ignored.
What it looks likeA column such as eye_color allows multiple rows to contain Blue because it has no UNIQUE constraint.
Why it failsINSERT OR IGNORE only skips an insertion when the new row would violate a constraint.
Do this insteadIdentify the UNIQUE constraint or another relevant constraint before relying on duplicate handling.
Common mistake Using SELECT after INSERT OR IGNORE without a unique lookup value.
What it looks likeSearching for a value in a column that permits several identical rows.
Why it failsThe SELECT may not identify one specific record when the value maps to multiple rows.
Do this insteadUse a value protected by a UNIQUE constraint when the goal is to retrieve one record's primary key.
Common mistake Treating an ignored insertion as an update.
What it looks likeAttempting to insert an existing username with different accompanying data.
Why it failsThe conflicting insertion is skipped; INSERT OR IGNORE does not replace the existing row.
Do this insteadUse this pattern only when reusing the existing record is the intended behavior.
Common mistake Using INSERT OR IGNORE when the program must report a duplicate.
What it looks likeA workflow requires different behavior for a newly registered username and an already registered username.
Why it failsThe pattern is designed to continue without raising an error for the violation.
Do this insteadUse an approach that explicitly checks or distinguishes the insertion result.
Apply the Workflow
A tags table stores a tag name under a UNIQUE constraint. The application receives the tag name python, but it does not know whether that tag already exists. Describe the two database actions you would use to ensure the tag exists and obtain its primary key.
Hints
- The first action should attempt the insertion without allowing a duplicate to raise an error.
- The second action should search by the unique tag name and return the tag's primary key.
- Explain why the UNIQUE constraint makes the lookup reliable.
Reusing a tag or creating it
An application needs the primary key for the tag named news, whether news is already stored or must be added.
- 1Attempt the insertion
Use INSERT OR IGNORE with news. A missing tag can be inserted, while an existing tag protected by UNIQUE causes the insertion to be skipped.
- 2Search for the tag
Use SELECT with the unique tag value news to retrieve its primary key.
- 3Use the returned key
The application can use the primary key to link another record to the tag.
The workflow continues with the primary key for the newly inserted or already existing news tag.
Essential Takeaways
- 1INSERT OR IGNORE silently skips an insertion that would violate a constraint and lets the program continue.
- 2A successful insertion changes the table; an ignored duplicate leaves the existing table row in place.
- 3A UNIQUE constraint is what makes duplicate handling meaningful and makes a follow-up SELECT reliable for one primary key.
- 4The two-step pattern is INSERT OR IGNORE followed by SELECT for workflows that need a record to exist and need its primary key.
- 5Use another approach when the application must know whether a new row was inserted rather than merely ensuring that a record exists.
At a glance
- INSERT OR IGNORE prevents a constraint violation from interrupting the program by skipping the conflicting insertion.
- Pairing it with SELECT lets an application retrieve the primary key of either a newly created or already existing record.
- The pattern depends on a UNIQUE constraint when duplicate values must map to exactly one row.
- Without a uniqueness constraint, repeated values are normally accepted unless another constraint is violated.
- This approach is best when the application needs a record to exist, not when it must distinguish a new insertion from an ignored duplicate.