多表关联查询时如何获取唯一行?附现有查询语句与样本数据
看起来你的查询现在大概率会出现重复数据,核心问题是没有指定表之间的关联条件,导致产生了笛卡尔积,另外可能单表内也存在多条匹配的记录。我来一步步帮你解决:
第一步:修复表关联逻辑
你当前用隐式逗号分隔表的写法,没有定义Account、Application、account_version之间的关联关系,这会让数据库返回所有表的组合数据,肯定会有大量重复。首先要改成显式JOIN,并指定关联键(比如假设三张表都通过acc_id关联,你需要根据实际表结构调整):
SELECT a.project_id, a.acc_name, a.project_name, a.iot, a.acc_id, a.active, b.app_fte, b.contact_person, c.cost_call_date FROM Account a -- 关联Application表,这里假设用acc_id关联,根据你的实际结构调整 JOIN Application b ON a.acc_id = b.acc_id -- 关联account_version表,同样假设用acc_id关联 JOIN account_version c ON a.acc_id = c.acc_id WHERE a.acc_name = 'GGG' AND EXTRACT(MONTH FROM c.cost_call_date) = 3;
另外,原查询里的a.acc_id in (Select acc_id from account where acc_name='GGG')可以简化成a.acc_name = 'GGG',效果完全一样,更高效。
第二步:去除重复行
如果修复关联后还是有重复,那说明某个表(比如account_version)里同一个acc_id在3月有多条记录,或者Application里同一个acc_id有多条数据。根据你的需求,有两种常用方案:
方案1:用DISTINCT直接去重
如果所有字段的重复都是多余的,直接在SELECT后加DISTINCT,让数据库返回唯一的字段组合:
SELECT DISTINCT a.project_id, a.acc_name, a.project_name, a.iot, a.acc_id, a.active, b.app_fte, b.contact_person, c.cost_call_date FROM Account a JOIN Application b ON a.acc_id = b.acc_id JOIN account_version c ON a.acc_id = c.acc_id WHERE a.acc_name = 'GGG' AND EXTRACT(MONTH FROM c.cost_call_date) = 3;
方案2:用窗口函数指定取某一条记录
如果需要明确取每个acc_id对应的最新/最早的版本记录,用ROW_NUMBER()窗口函数更灵活:
SELECT * FROM ( SELECT a.project_id, a.acc_name, a.project_name, a.iot, a.acc_id, a.active, b.app_fte, b.contact_person, c.cost_call_date, -- 按acc_id分组,按cost_call_date倒序排序,给每条记录标序号 ROW_NUMBER() OVER (PARTITION BY a.acc_id ORDER BY c.cost_call_date DESC) AS rn FROM Account a JOIN Application b ON a.acc_id = b.acc_id JOIN account_version c ON a.acc_id = c.acc_id WHERE a.acc_name = 'GGG' AND EXTRACT(MONTH FROM c.cost_call_date) = 3 ) AS sub_query -- 只取每组的第一条(也就是最新的那条记录) WHERE rn = 1;
如果要取最早的记录,把ORDER BY c.cost_call_date DESC改成ASC即可。如果Application表也有多条同acc_id的记录,你可以把PARTITION BY a.acc_id改成PARTITION BY a.acc_id, b.app_id(假设app_id是Application的主键),按需调整。
内容的提问来源于stack exchange,提问作者Kkunal

