Direct Answer
INSERT OR IGNORE INTO users (email, name)
VALUES ('a@example.com', 'Alice');
INSERT INTO users (email, name)
VALUES ('a@example.com', 'Alice')
ON CONFLICT(email) DO NOTHING;
Both forms require a conflict target: a PRIMARY KEY, UNIQUE constraint, or unique index. Without one, SQLite has no definition of "already exists."
Complete runnable example
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);
INSERT OR IGNORE INTO users (email, name)
VALUES ('a@example.com', 'Alice');
INSERT OR IGNORE INTO users (email, name)
VALUES ('a@example.com', 'Alice Again');
SELECT id, email, name FROM users;
The second insert is ignored; the existing row is not updated. If you need "insert or update," use ON CONFLICT DO UPDATE.
Which form should you use?
| Form | Behavior | Best for |
|---|---|---|
INSERT OR IGNORE | Skip the row on conflict | Idempotent imports and duplicate-tolerant loads |
ON CONFLICT DO NOTHING | Skip a specified conflict target | Clearer modern syntax |
ON CONFLICT DO UPDATE | Update the existing row | Upsert workflows such as settings sync |
WHERE NOT EXISTS | Insert based on a lookup | Complex conditions, still with a unique constraint for safety |
Insert or update: SQLite upsert
INSERT INTO users (email, name)
VALUES ('a@example.com', 'Alice Updated')
ON CONFLICT(email) DO UPDATE SET
name = excluded.name;
excluded refers to the row you attempted to insert. It is not the same syntax as MySQL's ON DUPLICATE KEY UPDATE.
Difference from MySQL
MySQL commonly uses INSERT IGNORE or INSERT ... ON DUPLICATE KEY UPDATE. SQLite uses INSERT OR IGNORE and ON CONFLICT. Both rely on unique keys to detect conflicts, but the syntax and details differ. For MySQL insert patterns, return to SQL data manipulation.