单条SQL实现存在则取值、不存在则插B表后写入A表
单SQL实现跨表插入带不存在则新增逻辑方案
核心逻辑
先确保B表中action='test'的记录存在,再读取对应的B2字段值写入A表,全程单语句执行,依赖数据库原子性保证并发场景下的数据一致性。
前置注意项:
- B表的
action字段必须创建唯一约束/唯一索引,否则并发场景下可能插入重复的action='test'记录,导致逻辑异常 - 新插入B表行的B2值需要匹配业务生成规则:如果B2是自增字段填
DEFAULT,如果是UUID类字段填对应生成函数,按实际业务规则替换即可
不同数据库对应写法
PostgreSQL
PG原生支持CTE内执行DML+RETURNING返回值,写法最简洁,不需要额外兼容:
WITH b_record AS ( -- 先查询已存在的符合条件记录 SELECT B2 FROM B WHERE action = 'test' UNION ALL -- 无符合记录则插入新行,返回新生成的B2 INSERT INTO B(action, B2) SELECT 'test', '替换为你的B2字段生成规则' WHERE NOT EXISTS (SELECT 1 FROM B WHERE action = 'test') RETURNING B2 ) INSERT INTO A(A1, A2) SELECT 'A1 Value', B2 FROM b_record;
该写法中如果B表已有匹配记录,后续INSERT逻辑不会触发,直接复用已有B2;无匹配记录时自动插入新行,读取新B2写入A表。
MySQL 8.0+
需要配合ON DUPLICATE KEY UPDATE实现不存在则插入,执行完B表写入后直接关联查询对应B2值:
INSERT INTO A(A1, A2) SELECT 'A1 Value', B.B2 FROM ( -- 先写入B表,已存在则不做修改 INSERT INTO B(action, B2) VALUES('test', '替换为你的B2字段生成规则') ON DUPLICATE KEY UPDATE action = action ) AS tmp JOIN B ON B.action = 'test';
如果使用MySQL 5.x版本,无法在子查询中嵌套INSERT语句,不能严格满足单语句实现要求,建议升级版本后使用上述写法。
原写法问题说明
你最初编写的语句仅在B表存在匹配记录时生效,当无匹配记录时子查询返回NULL,不会自动触发B表的新行插入,因此无法满足需求。
内容的提问来源于stack exchange,提问作者Jey
相关产品推荐
相关产品推荐

