← Back to SQL Tutorial

SQLite Insert If Not Exists

In SQLite, do not copy MySQL's ON DUPLICATE KEY UPDATE. Use a unique constraint plus INSERT OR IGNORE or ON CONFLICT DO NOTHING.

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?

FormBehaviorBest for
INSERT OR IGNORESkip the row on conflictIdempotent imports and duplicate-tolerant loads
ON CONFLICT DO NOTHINGSkip a specified conflict targetClearer modern syntax
ON CONFLICT DO UPDATEUpdate the existing rowUpsert workflows such as settings sync
WHERE NOT EXISTSInsert based on a lookupComplex 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.