SQL多表插入实现:仅当主表event_headers无对应记录时执行插入
解决方案
方案1:使用MySQL事务 + 行计数判断(推荐,适配你现有SQL脚本逻辑)
前提:你已经为event_headers表的session_id字段设置了唯一索引,这是INSERT IGNORE能正常去重的基础。
你可以把SQL改成如下结构:
START TRANSACTION; -- 先插入header表 INSERT IGNORE INTO `event_headers` (`session_id`, [...]) VALUES ('89131', [...]); -- 记录上一步插入的影响行数 SET @insert_success = ROW_COUNT(); -- 只有插入成功(不存在重复)才执行后续操作 IF @insert_success > 0 THEN INSERT INTO `event_records` (`event_header_session_id`, [...]) VALUES ('89131', [...]), ('89131', [...]), ('89191', [...]); -- 你要更新的第三个表的语句也放在这里 END IF; COMMIT;
逻辑说明:
INSERT IGNORE插入重复的session_id时不会报错,只会返回0的影响行数- 用
ROW_COUNT()拿到上一步操作的影响行数后判断,等于1说明是新插入的header,就执行后续的子表插入、其他表更新操作 - 事务包裹保证数据一致性,不会出现header插了、子表没插的异常情况
方案2:单SQL带条件插入(不需要写存储过程/判断逻辑)
如果你不想用事务和IF判断,可以给后续的INSERT语句加存在性校验:
INSERT IGNORE INTO `event_headers` (`session_id`, [...]) VALUES ('89131', [...]); INSERT INTO `event_records` (`event_header_session_id`, [...]) SELECT * FROM ( SELECT '89131' as `event_header_session_id`, [...] UNION ALL SELECT '89131' as `event_header_session_id`, [...] UNION ALL SELECT '89191' as `event_header_session_id`, [...] ) AS tmp WHERE NOT EXISTS ( SELECT 1 FROM `event_headers` WHERE `session_id` = '89131' );
这种写法不需要事务支持,所有逻辑都在单条INSERT语句里完成,适合不支持自定义事务的执行场景。
方案3:C#代码层面判断(逻辑更直观)
如果你对SQL语法不熟悉,也可以在C#代码里先做校验:
- 先执行查询
SELECT COUNT(1) FROM event_headers WHERE session_id = @sessionId拿到存在性结果 - 如果返回值为0,再依次执行event_headers插入、event_records插入、第三个表更新的语句
- 所有操作建议包裹在C#的TransactionScope里保证一致性
注意事项
- 必须确保
event_headers的session_id字段设置唯一索引,否则所有去重和判断逻辑都会失效 - 如果需要批量处理多个session_id,建议对每个session_id单独走判断逻辑,不要混写多个session的插入语句
内容的提问来源于stack exchange,提问作者Danny
相关产品推荐
相关产品推荐

