从含mm表的7个MariaDB表取数据时冗余行过多求助
嘿,你遇到的这个冗余行问题我太熟了——多表JOIN尤其是涉及多对多关系的时候,很容易因为关联表的多条记录把主表数据给“复制”好几遍。我给你几个实用的解决思路,你可以根据自己的业务需求选:
先搞清楚你真正需要的是什么数据:如果你的核心需求是获取酒店的基础信息,而关联的职位、联系人等只是辅助信息,那没必要把所有关联表的明细都拉出来。比如一个酒店对应10个职位,直接JOIN的话酒店信息会重复10次,这时候要么汇总关联数据,要么只取关键的一条。
用
DISTINCT快速去重(但别乱⽤):如果你的查询结果里,酒店的核心字段(name、address这些)是唯一的,冗余只是因为关联表的多条记录导致的,可以在SELECT后面加DISTINCT来过滤重复行:SELECT DISTINCT h.name, h.address, h.zipcode, h.city, h.association, r.name_de, f.first_name, f.last_name, f.email, p.year, j.name FROM `tx_gipdhotels_domain_model_hotel` AS h JOIN `tx_gipdhotels_hotel_jobs_mm` AS hj ON h.uid = hj.uid_local JOIN `tx_gipdhotels_domain_model_jobs` AS j ON j.uid = hj.uid_foreign -- 补全剩下的JOIN语句注意:如果业务上需要保留所有关联的明细(比如每个酒店的每个职位都要单独一条记录),那
DISTINCT会删掉有用的数据,这个方法只适合核心数据唯一的场景。用聚合函数汇总多对多关联数据:如果一个酒店对应多个职位/联系人,你可以把这些关联值合并成一个字符串,这样每条酒店记录只会出现一次。比如MySQL用
GROUP_CONCAT,PostgreSQL用STRING_AGG:SELECT h.name, h.address, h.zipcode, h.city, h.association, r.name_de, f.first_name, f.last_name, f.email, p.year, GROUP_CONCAT(DISTINCT j.name SEPARATOR ', ') AS job_names FROM `tx_gipdhotels_domain_model_hotel` AS h JOIN `tx_gipdhotels_hotel_jobs_mm` AS hj ON h.uid = hj.uid_local JOIN `tx_gipdhotels_domain_model_jobs` AS j ON j.uid = hj.uid_foreign -- 补全剩下的JOIN语句 GROUP BY h.name, h.address, h.zipcode, h.city, h.association, r.name_de, f.first_name, f.last_name, f.email, p.year这样既保留了所有关联的职位信息,又不会让酒店数据重复。
检查你的JOIN条件是否正确:有时候冗余行是因为JOIN条件写错了——比如不小心用了非唯一的字段关联,或者漏加了关联条件导致全表笛卡尔积。仔细核对每个JOIN的ON子句,确保是用主键/唯一键关联的(比如中间表的
uid_local对应酒店的uid,uid_foreign对应职位的uid),别让无关的行也被关联进来。用子查询拆分复杂关联:如果关联的表太多,逻辑太绕,可以把多对多的部分拆成子查询,先拿酒店的核心数据,再通过子查询获取关联信息,避免一次性JOIN所有表导致的数据膨胀:
SELECT h.name, h.address, h.zipcode, h.city, h.association, r.name_de, f.first_name, f.last_name, f.email, p.year, (SELECT GROUP_CONCAT(j.name SEPARATOR ', ') FROM `tx_gipdhotels_hotel_jobs_mm` AS hj JOIN `tx_gipdhotels_domain_model_jobs` AS j ON j.uid = hj.uid_foreign WHERE hj.uid_local = h.uid) AS job_names FROM `tx_gipdhotels_domain_model_hotel` AS h -- 一对一关联的表可以直接JOIN,比如r、f、p这些如果是和酒店一一对应的话 JOIN `tx_gipdhotels_domain_model_xxx` AS r ON ... JOIN `tx_gipdhotels_domain_model_xxx` AS f ON ... JOIN `tx_gipdhotels_domain_model_xxx` AS p ON ...
如果还是找不到问题,你可以试着逐步JOIN表——先只JOIN酒店和职位表,看看结果有没有重复,再加入下一个表,这样就能快速定位到是哪个表导致的冗余啦。
内容的提问来源于stack exchange,提问作者Kathara

