PostgreSQL 类似于Mysql的replace into的功能

PostgreSQL中的数据更新与替换操作
这篇博客探讨了在PostgreSQL中如何处理数据批量新增和更新的问题,使用INSERT INTO...ON CONFLICT语句来替代MySQL中的REPLACE INTO。通过示例展示了DOnothing和DOUPDATE两种策略,当主键冲突时,可以不做任何操作或者更新已有记录的年龄字段。这对于维护数据库的一致性和完整性至关重要。

最近搞报表统计
数据是从另一个平台通过定时器拉取的。
新的数据批量新增,同时旧的数据还要进行更新的操作。

mysql 有类似的功能 replace into
但是现在用的是PostgreSQL
查了一下, 发现可以用INSERT INTO ...ON conflict(x) DO xxx

建一张测试表
select * from table_test

在这里插入图片描述

DO nothing测试
-- 一旦发现主键冲突,不做任何操作,查询和之前一样
INSERT INTO table_test(name, age)
VALUES('zhangsan',3),('lsi',3),('wangwu',3)
ON conflict(name) 
DO nothing;

在这里插入图片描述

DO update测试
-- 一旦发现主键冲突,做更新操作
INSERT INTO table(name, age)
VALUES('zhangsan',3),('lsi',3),('wangwu',3)
ON conflict(name) 
DO UPDATE SET age = EXCLUDED.age ;

在这里插入图片描述

`REPLACE INTO idm_tenant_use ...` 是一种 **MySQL 特有的 SQL 语句**,用于实现“**插入或替换**”的功能。 --- ### 回答问题:`REPLACE INTO` 的功能是什么? `REPLACE INTO` 的作用是: > **尝试插入一条新记录,如果表中已存在主键或唯一索引冲突(Duplicate Key),则先删除旧记录,再插入新记录。** 它是一种比 `INSERT INTO` 更“暴力”的插入方式,常用于希望确保某条数据最终存在于表中,并以新值覆盖旧值的场景。 --- ### 工作原理(以 `idm_tenant_use` 表为例): 假设表结构如下: ```sql CREATE TABLE idm_tenant_use ( id BIGINT PRIMARY KEY AUTO_INCREMENT, tenant_id VARCHAR(64) UNIQUE, -- 唯一约束 use_count INT, updated_time DATETIME ); ``` 执行以下 SQL: ```sql REPLACE INTO idm_tenant_use (tenant_id, use_count, updated_time) VALUES ('t001', 5, NOW()); ``` #### 执行流程: 1. MySQL 检查 `tenant_id='t001'` 是否违反了 **主键或唯一键约束**; 2. 如果不存在冲突 → 相当于 `INSERT INTO`,直接插入; 3. 如果已存在 `tenant_id='t001'` 的记录 → **先 DELETE 旧行,再 INSERT 新行**; 4. 结果:表中只有一条新数据,旧数据被彻底移除并重建。 --- ### 与 `INSERT ... ON DUPLICATE KEY UPDATE` 的区别 | 特性 | `REPLACE INTO` | `INSERT INTO ... ON DUPLICATE KEY UPDATE` | |------|----------------|-------------------------------------------| | 实现机制 | 删除 + 插入 | 更新原有行 | | 主键变化 | 可能改变(如自增 ID 会变) | 不变 | | 触发器 | 触发 `DELETE` 和 `INSERT` 触发器 | 只触发 `INSERT` / `UPDATE` | | 性能 | 稍慢(涉及删除和重建) | 更高效(原地更新) | | 字段默认值 | 所有字段必须显式赋值,否则用默认值填充 | 可选择性更新部分字段 | | 使用建议 | 简单替换整行数据 | 推荐用于精确控制更新字段 | --- ### 示例对比 #### 使用 `REPLACE INTO` ```sql REPLACE INTO idm_tenant_use (tenant_id, use_count, updated_time) VALUES ('t001', 5, '2025-04-05 10:00:00'); ``` - 若 `tenant_id='t001'` 已存在,则整行被删除后重新插入。 - 自增主键 `id` 可能发生变化(变成新的值)。 - 所有没有指定的字段将设为 `DEFAULT` 或 `NULL`。 #### 使用 `INSERT ... ON DUPLICATE KEY UPDATE` ```sql INSERT INTO idm_tenant_use (tenant_id, use_count, updated_time) VALUES ('t001', 5, '2025-04-05 10:00:00') ON DUPLICATE KEY UPDATE use_count = use_count + 1, updated_time = VALUES(updated_time); ``` - 若冲突,只更新 `use_count` 和 `updated_time`,其他字段保持不变。 - `id` 不变,性能更高,更安全。 --- ### 注意事项 1. ⚠️ **可能导致主键变更**:由于是“删+插”,自增 ID 会被重置为新值,外键引用可能失效。 2. ⚠️ **触发级联操作**:如果有外键约束带 `ON DELETE CASCADE`,删除旧行会连带删除关联数据。 3. ⚠️ **非标准 SQL**:`REPLACE INTO` 是 MySQL 特有语法,在 Oracle、PostgreSQLSQL Server 中不可用。 4. ⚠️ **性能开销大**:相比更新操作,多了一次删除和重建,还可能影响索引和缓存。 --- ### 底层等价逻辑(伪代码) ```sql IF EXISTS (SELECT * FROM idm_tenant_use WHERE 冲突的唯一键匹配) THEN DELETE FROM idm_tenant_use WHERE 冲突键匹配; INSERT INTO idm_tenant_use VALUES (...); ELSE INSERT INTO idm_tenant_use VALUES (...); END IF; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值