多左连接导致PHP+SQL Server查询结果重复问题求助
问题根源分析
重复行的核心原因是主表tbl_OCV_Worksheet的某条记录(位置7的Serial_Num)在关联的子表(如tbl_CellTrack_AcidFiller、tbl_Stage_Check等)中存在多条匹配记录,左连接会将主表行与子表的每条匹配记录组合,导致主表行被重复展开(也就是你说的“聚合扇出”)。
解决步骤
1. 先定位重复源头
执行以下SQL,检查位置7的Serial_Num在各关联表中的记录数,找到返回值大于1的表:
-- 检查酸填充表的匹配记录数 SELECT COUNT(*) FROM tbl_CellTrack_AcidFiller WHERE BatteryID = '位置7的Serial_Num值'; -- 检查阶段检查表的匹配记录数 SELECT COUNT(*) FROM tbl_Stage_Check WHERE BatteryID = '位置7的Serial_Num值'; -- 检查填充工位表的匹配记录数 SELECT COUNT(*) FROM tbl_CellTrack_StuffStation ss JOIN tbl_Stage_Check sc ON ss.EncapID = sc.EncapID WHERE sc.BatteryID = '位置7的Serial_Num值'; -- 检查泄漏检测表的匹配记录数 SELECT COUNT(*) FROM tbl_CellTrack_LeakStation WHERE BatteryID = '位置7的Serial_Num值';
2. 对子表进行去重处理
针对返回多条记录的子表,使用ROW_NUMBER()窗口函数按关联字段分组,只取一条有效记录(比如最新的一条),避免主表行被重复展开。
完整修正后的查询代码
public function SelectCircuitInfo($circuitId) { $this->db->query("SELECT wk.*, af.AcidWeight, af.AcidChillerTemp, ss.BackL, ss.FrontL, ss.BkR, ss.FtR, ls.Rersult1, af.Prefillweight, af.PostFillWeight, af.StartTime, af.EndTime FROM tbl_OCV_Worksheet wk -- 酸填充表去重:按BatteryID分组,取最新的一条记录 LEFT JOIN ( SELECT BatteryID, AcidWeight, AcidChillerTemp, Prefillweight, PostFillWeight, StartTime, EndTime FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY BatteryID ORDER BY StartTime DESC) AS rn FROM tbl_CellTrack_AcidFiller ) af_sub WHERE rn = 1 ) af ON wk.Serial_Num = af.BatteryID -- 阶段检查表去重:按BatteryID分组,取最新的一条记录(替换成实际时间字段) LEFT JOIN ( SELECT BatteryID, EncapID FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY BatteryID ORDER BY CreateTime DESC) AS rn FROM tbl_Stage_Check ) sc_sub WHERE rn = 1 ) sc ON wk.Serial_Num = sc.BatteryID -- 填充工位表去重:按EncapID分组,取最新的一条记录(替换成实际时间字段) LEFT JOIN ( SELECT EncapID, BackL, FrontL, BkR, FtR FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY EncapID ORDER UpdateTime DESC) AS rn FROM tbl_CellTrack_StuffStation ) ss_sub WHERE rn = 1 ) ss ON sc.EncapID = ss.EncapID -- 泄漏检测表去重:按BatteryID分组,取最新的一条记录(替换成实际时间字段) LEFT JOIN ( SELECT BatteryID, Rersult1 FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY BatteryID ORDER BY TestTime DESC) AS rn FROM tbl_CellTrack_LeakStation ) ls_sub WHERE rn = 1 ) ls ON wk.Serial_Num = ls.BatteryID WHERE wk.Circuit_Id = :cid ORDER BY cast(Position_Num as int)"); $this->db->bind(":cid", $circuitId); return $this->db->resultSet(); }
3. 可选:用聚合函数替代去重
如果子表的重复记录不需要取最新,而是需要聚合值(比如平均酸重、最大温度),可以用GROUP BY+聚合函数:
LEFT JOIN ( SELECT BatteryID, MAX(AcidWeight) AS AcidWeight, MAX(AcidChillerTemp) AS AcidChillerTemp FROM tbl_CellTrack_AcidFiller GROUP BY BatteryID ) af ON wk.Serial_Num = af.BatteryID
内容的提问来源于stack exchange,提问作者torain20
相关产品推荐
相关产品推荐

