如何将SQLAlchemy的UPSERT操作为?
摘要:前言 SQLite 和 PostgreSQL 都支持 UPSERT 操作,即"有则更新,无则新增"。冲突列必须有唯一约束。 语法: PostgreSQL: INSERT ... ON CO
前言
SQLite 和 PostgreSQL 都支持 UPSERT 操作,即"有则更新,无则新增"。冲突列必须有唯一约束。
语法:
PostgreSQL: INSERT ... ON CONFLICT (column) DO UPDATE/NOTHING
SQLite: INSERT ... ON CONFLICT(column) DO UPDATE/NOTHING。注意括号位置
场景
PostgreSQL
SQLite
说明
基本 UPSERT
ON CONFLICT (col) DO UPDATE SET ...
ON CONFLICT(col) DO UPDATE SET ...
括号位置略有不同
冲突忽略
ON CONFLICT (col) DO NOTHING
ON CONFLICT(col) DO NOTHING
相同
引用新值
EXCLUDED.col
excluded.col
PostgreSQL 大写,SQLite 小写
返回结果
RETURNING *
RETURNING *
相同
条件更新
WHERE condition
不支持 WHERE
SQLite 限制
注意事项
冲突列必须有唯一约束
PostgreSQL 和 SQLite 的语法相似,但仍有细微差别。使用原生 SQL 时需要注意。
SQLite 在 UPSERT 时不支持 WHERE 子句,需要改用 CASE 表达式或应用层过滤。
SQLite 3.35+ 版本才支持 RETURNING
EXCLUDED 和 RETURNING
EXCLUDED
EXCLUDED 表示冲突时被拦截的新值。
INSERT INTO users (email, name, age)
VALUES ('test@example.com', '新名字', 30)
ON CONFLICT (email) DO UPDATE SET
name = EXCLUDED.name, -- ← 引用新值 "新名字"
age = EXCLUDED.age -- ← 引用新值 30
场景
表达式
含义
示例值
原表字段
users.name
冲突行的当前值
"老名字"
新值字段
EXCLUDED.name
试图插入的新值
"新名字"
混合计算
users.age + EXCLUDED.age
原值 + 新值
25 + 30 = 55
示例 1:累加库存
-- 商品库存累加:原库存 100 + 新增 50 = 150
INSERT INTO products (sku, stock)
VALUES ('IPHONE15', 50)
ON CONFLICT (sku) DO UPDATE SET
stock = products.stock + EXCLUDED.stock -- 100 + 50
RETURNING stock;
示例 2:仅更新非空字段
-- 如果新值为 NULL,保留原值
INSERT INTO users (email, name, age)
VALUES ('test@example.com', '新名字', NULL)
ON CONFLICT (email) DO UPDATE SET
name = COALESCE(EXCLUDED.name, users.name), -- 新名字
age = COALESCE(EXCLUDED.age, users.age) -- 保留原 age
示例 3:时间戳更新
-- 更新时刷新 updated_at
INSERT INTO users (email, name)
VALUES ('test@example.com', '新名字')
ON CONFLICT (email) DO UPDATE SET
name = EXCLUDED.name,
updated_at = NOW() -- PostgreSQL
-- updated_at = CURRENT_TIMESTAMP -- SQLite
RETURNING
RETURNING 用于返回操作结果。
