带外键关联的两张数据表的数据复制及外键匹配方案咨询
解决方案:批量复制评论并同步关联评分记录
嘿,手动用CSV处理这种场景确实太折磨人了,尤其是数据量大、还有删除记录和评分项数量不一致的情况,完全可以用SQL来批量操作,既能保证效率,又能精准匹配外键。我给你分步骤讲清楚怎么实现,还有关于表结构的疑问也一起解答:
一、用SQL实现评论复制+评分同步
核心思路是先复制目标评论记录,同时记录旧评论ID和新评论ID的映射关系,再根据这个映射同步评分表的记录。不同数据库的语法略有区别,我给你写常用的MySQL和PostgreSQL版本:
1. MySQL版本
-- 第一步:创建临时表存储新旧评论ID的映射 CREATE TEMPORARY TABLE review_mapping ( old_id_review INT, new_id_review INT ); -- 复制id_lang=2的评论,将id_lang改为1,插入到reviews表 INSERT INTO reviews (id_lang, email, text) SELECT 1, email, text FROM reviews WHERE id_lang = 2; -- 填充映射表:假设id_review是自增主键,计算新插入记录的起始ID,然后对应原记录的ID SET @start_new_id = (SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'reviews') - (SELECT COUNT(*) FROM reviews WHERE id_lang = 2); INSERT INTO review_mapping (old_id_review, new_id_review) SELECT id_review, @start_new_id := @start_new_id + 1 FROM reviews WHERE id_lang = 2 ORDER BY id_review; -- 第二步:根据映射表,同步grade表的记录 INSERT INTO grade (id_review, id_criterion, grade) SELECT rm.new_id_review, g.id_criterion, g.grade FROM grade g JOIN review_mapping rm ON g.id_review = rm.old_id_review;
2. PostgreSQL版本
PostgreSQL的RETURNING子句能直接获取插入后的新ID,用起来更省心:
-- 第一步:先把要复制的原评论存起来,再插入新评论并生成映射 WITH original_reviews AS ( SELECT id_review, email, text FROM reviews WHERE id_lang = 2 ), inserted_reviews AS ( INSERT INTO reviews (id_lang, email, text) SELECT 1, email, text FROM original_reviews RETURNING id_review AS new_id_review, email, text ) -- 将新旧ID的映射存入临时表 SELECT or.id_review AS old_id_review, ir.new_id_review INTO TEMPORARY TABLE review_mapping FROM original_reviews or JOIN inserted_reviews ir ON or.email = ir.email AND or.text = ir.text; -- 第二步:同步评分记录 INSERT INTO grade (id_review, id_criterion, grade) SELECT rm.new_id_review, g.id_criterion, g.grade FROM grade g JOIN review_mapping rm ON g.id_review = rm.old_id_review;
关键提示
- 临时表
review_mapping是核心,它能精准关联原评论和新生成的评论,不管原表有没有删除过记录,也不管每个评论对应的评分项数量多少,都能批量同步,不会出错。 - 如果你的
reviews表还有其他需要复制的字段,比如创建时间之类的,只要在INSERT ... SELECT里加上对应的字段就行,保证除了id_lang改成1,其他和原记录一致。
二、关于修改表结构的疑问:能否让同一id_review对应不同id_lang?
绝对不建议这么做!因为id_review是reviews表的主键,主键的硬性要求就是唯一性,同一ID对应不同语言的记录会直接违反主键约束,数据库根本不允许这种定义。
如果你的业务需求是“同一评论内容对应多语言版本”,更合理的表结构设计应该是拆分表:
- 新增
review_core表:存储评论的通用信息,比如id_review(主键)、email、create_time等; - 新增
review_translations表:字段包括id_review(外键关联review_core)、id_lang、text,把(id_review, id_lang)设为联合主键。
这样同一个评论可以对应多个语言版本,后续添加新语言时只需要在review_translations里插入新行就行,grade表还是关联id_review,不需要重复复制评分记录,逻辑更清晰,也更高效。
内容的提问来源于stack exchange,提问作者Petteri Pucilowski
相关产品推荐
相关产品推荐

