SQLite 一行SQL实现有则更新无则插入,多个条件,复杂条件

本文介绍如何使用SQLite通过一条SQL语句实现有则更新无则插入的功能,并附带示例代码。利用REPLACE INTO语句结合唯一索引,可以在不额外判断的情况下高效地完成操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SQLite 一行SQL实现有则更新无则插入,多个条件,复杂条件

示例代码:https://github.com/miqt/MultiProgressKV/blob/master/MultiProgressKV/src/main/java/com/miqt/multiprogresskv/DBHelper.java

例如想实现以下逻辑

if (db has name ==小明 && 身高 == 170cm)
	update 。。。。
else 
	insert 。。。。

可以参考以下SQL:

CREATE TABLE [TABLE_NAME](
  [id] INTEGER PRIMARY KEY AUTOINCREMENT, 
  [name] TEXT NOT NULL , 
  [attr] TEXT NOT NULL , 
  [value] TEXT NOT NULL );

CREATE UNIQUE INDEX [TABLE_NAME]
ON [TABLE_NAME](
  [name], 
  [attr]);

CREATE UNIQUE INDEX [TABLE_NAME] 声明了只有name,和attr都重复才算唯一索引,这适用于类似插入一本书的场景,一本书的书名和作者只可能有一个,而单独的书名,和作者本身,可能对应很多本书。

以下语句执行,则是有则更新,无则插入的效果,以下SQL执行多次只会生成一行结果,而修改name,或者attr任意一个列,则又会新插入一个。

REPLACE INTO TABLE_NAME
  (
    name ,
    attr ,
    value
  )
VALUES
  (
    '《西游记》' ,
    '作者' ,  
    '吴承恩'
  ) ;
<think>好的,我现在需要解决用户的问题:如何在 SQLite3 中实现插入一条数据,如果存在则更新,不存在则插入。用户之前询问过如何用 Golang 将 MySQL 表转为 SQLite 表,现在可能是在迁移数据后,需要处理数据插入更新逻辑。 首先,我需要回忆 SQLite 的相关语法。记得 SQLite 有 INSERT OR REPLACE 语句,但不确定是否适用所有情况。另外,还有 UPSERT 功能,但需要确认 SQLite 的版本支持情况。用户可能希望一个通用的方法,兼容不同版本。 然后,考虑主键冲突的情况。当插入数据主键已存在时,触发更新操作。这可以通过 ON CONFLICT 子句处理。需要明确语法结构,比如 INSERT INTO ... ON CONFLICT(...) DO UPDATE SET ...。 另外,用户可能在实际应用中需要具体示例,特别是字段较多时如何处理。需要提供清晰的例子,说明如何构建 SQL 语句,尤其是占位符的使用,以及如何映射需要更新的字段。 还要注意,如果表没有定义主键或唯一约束,ON CONFLICT 可能不起作用,需要提醒用户这一点。此外,区分 REPLACE 和 UPDATE 的区别,比如 REPLACE 会删除原有行再插入,可能影响自增ID或其他字段,而 UPDATE 只修改指定字段。 最后,可能需要给出在 Golang 中使用 sqlite3 驱动的示例代码,因为用户之前的问题涉及 Golang,所以提供代码片段会更有帮助。需要导入正确的驱动,处理错误,并演示如何执行带有冲突处理的插入语句。 总结步骤:确定冲突解决的语法,提供示例,说明注意事项,并给出代码示例。确保用户能够根据指导实现存在更新、不存在插入的功能,同时避免常见陷阱。</think>以下是 SQLite3 中实现"存在则更新,不存在则插入"的三种常用方法及详细说明: ### 一、基础语法原理 在 SQLite实现该功能的核心是使用 `ON CONFLICT` 子句,其标准语法结构为: ```sql INSERT INTO table_name (column_list) VALUES (value_list) ON CONFLICT(conflict_target) DO UPDATE SET column1 = excluded.column1, ...; ``` ### 二、具体实现方法 #### 方法1:使用 UPSERT (SQLite 3.24+) ```sql -- 假设 users 表有主键 id INSERT INTO users (id, name, age) VALUES (1, '张三', 30) ON CONFLICT(id) DO UPDATE SET name = excluded.name, age = excluded.age; ``` #### 方法2:使用 REPLACE INTO ```sql REPLACE INTO users (id, name, age) VALUES (1, '张三', 30); ``` ⚠️ 注意:这会先删除旧记录再插入新记录,可能导致自增ID改变 #### 方法3:传统两步操作 ```sql UPDATE users SET name='张三', age=30 WHERE id=1; INSERT INTO users (id, name, age) SELECT 1, '张三', 30 WHERE (SELECT changes() = 0); ``` ### 三、Golang 实现示例 ```go func upsertUser(db *sql.DB, user User) error { // 使用命名参数更清晰 query := ` INSERT INTO users (id, name, age) VALUES (?, ?, ?) ON CONFLICT(id) DO UPDATE SET name = excluded.name, age = excluded.age` _, err := db.Exec(query, user.ID, user.Name, user.Age) return err } ``` ### 四、关键注意事项 1. **唯一约束要求**: - 必须存在 `UNIQUE` 约束或 `PRIMARY KEY` - 冲突目标列需明确指定(如:`ON CONFLICT(email)`) 2. **字段更新策略**: - 使用 `excluded.` 前缀访问新值 - 可选择性更新部分字段 ```sql ON CONFLICT(id) DO UPDATE SET name = COALESCE(excluded.name, name), age = excluded.age ``` 3. **性能优化**: - 批量操作时使用事务 - 对冲突列建立合适索引 ```sql CREATE UNIQUE INDEX idx_users_email ON users(email); ``` 4. **特殊类型处理**: ```go // 处理时间类型 _, err = db.Exec(..., createdAt.Format(time.RFC3339)) // 处理NULL值 var nullableName sql.NullString if user.Name != "" { nullableName = sql.NullString{String: user.Name, Valid: true} } ``` ### 五、完整工作流程 1. 创建带唯一约束的表 ```sql CREATE TABLE users ( id INTEGER PRIMARY KEY, email TEXT UNIQUE, name TEXT NOT NULL, age INTEGER ); ``` 2. 执行UPSERT操作 ```sql INSERT INTO users (id, email, name, age) VALUES (1, 'zhangsan@example.com', '张三', 30) ON CONFLICT(email) DO UPDATE SET name = excluded.name, age = excluded.age; ``` 3. 验证结果 ```sql SELECT * FROM users WHERE email = 'zhangsan@example.com'; ``` ### 六、不同场景处理建议 1. **全量更新**:`SET column = excluded.column` 2. **条件更新**: ```sql ON CONFLICT(id) DO UPDATE SET age = excluded.age WHERE excluded.age > 18 ``` 3. **部分保留**: ```sql ON CONFLICT(id) DO UPDATE SET name = excluded.name || ' (updated)' ``` 建议优先使用标准UPSERT语法(方法1),需要 SQLite 3.24+ 版本支持。对于旧版本可结合事务实现类似效果,确保操作的原子性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

痕迹丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值