多表查询生成结果表:Case语句致重复行及Damage最大化问题
解决CASE WHEN导致重复行的问题
嘿,我来帮你搞定这个重复行的问题!咱们先理清楚问题出在哪:
你当前的查询用了笛卡尔积连接(直接把三个表丢在FROM里,没指定表之间的关联条件),再加上WHERE里的IN子句筛选,这会导致符合条件的快速技能(f)和蓄力技能(c)组合,和Pokemon_Types_And_Moves中所有Beedrill的记录挨个匹配。如果Pokemon_Types_And_Moves里有多条Beedrill的条目,或者同一条目下的属性有的匹配快速技能类型、有的不匹配,就会生成两条Damage值不同的行——一条是原数值,一条是乘1.2倍的数值。而SELECT DISTINCT因为Damage字段值不一样,根本没法去重。
你的需求是保留每个(f.Name, c.Name)组合下最大的Damage值(也就是触发1.2倍系数的那个,毕竟它更大),所以咱们得用分组聚合来替代DISTINCT,直接取最大值。
下面是修改后的SQL代码:
SELECT f.Name as 'Fast Move', MAX(CASE WHEN ptm.Primary_Type = f.Type OR ptm.Secondary_Type = f.Type THEN f.Damage * 1.2 ELSE f.Damage END) as 'Damage', f.DPS as 'Fast Move DPS', c.Name as 'Charged Move', c.Damage as 'Charged Move Damage', c.DPS as 'Charged Move DPS', ((f.Cooldown * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Time) as 'Full Cycle Time', ((f.damage * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Damage) as 'Full Cycle Damage', ROUND( ((f.damage * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Damage) / ((f.Cooldown * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Time), 2 ) as 'Full Cycle DPS' FROM Fast_Moves f JOIN Pokemon_Types_And_Moves ptm ON f.Name IN (ptm.Fast_Move_1, ptm.Fast_Move_2, ptm.Fast_Move_3) JOIN Charged_Moves c ON c.Name IN (ptm.Charged_Move_1, ptm.Charged_Move_2, ptm.Charged_Move_3) WHERE ptm.Pokemon_Name = 'Beedrill' GROUP BY f.Name, f.DPS, c.Name, c.Damage, c.DPS, ((f.Cooldown * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Time), ((f.damage * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Damage) ORDER BY f.Name, c.Name;
关键修改点说明:
- 替换笛卡尔积为JOIN:用JOIN明确表之间的关联条件,避免不必要的重复匹配,逻辑也更清晰。
- 用MAX()取最大Damage:对每个技能组合(f.Name + c.Name)以及其他不需要聚合的字段分组,直接取Damage的最大值——这样只要有一次触发1.2倍系数的情况,就会保留这个更大的值,自动丢掉原数值的冗余行。
- 简化WHERE子句:直接在JOIN条件中筛选Beedrill的技能,WHERE只保留Pokemon_Name的过滤,可读性更强。
如果Pokemon_Types_And_Moves里有很多重复的Beedrill技能记录,还可以先用CTE把技能去重,再关联查询,这样效率更高:
-- 先提取Beedrill的所有技能(去重) WITH BeedrillMoves AS ( SELECT DISTINCT UNNEST(ARRAY[Fast_Move_1, Fast_Move_2, Fast_Move_3]) AS FastMove, UNNEST(ARRAY[Charged_Move_1, Charged_Move_2, Charged_Move_3]) AS ChargedMove, Primary_Type, Secondary_Type FROM Pokemon_Types_And_Moves WHERE Pokemon_Name = 'Beedrill' ) SELECT f.Name as 'Fast Move', MAX(CASE WHEN bm.Primary_Type = f.Type OR bm.Secondary_Type = f.Type THEN f.Damage * 1.2 ELSE f.Damage END) as 'Damage', f.DPS as 'Fast Move DPS', c.Name as 'Charged Move', c.Damage as 'Charged Move Damage', c.DPS as 'Charged Move DPS', ((f.Cooldown * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Time) as 'Full Cycle Time', ((f.damage * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Damage) as 'Full Cycle Damage', ROUND( ((f.damage * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Damage) / ((f.Cooldown * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Time), 2 ) as 'Full Cycle DPS' FROM BeedrillMoves bm JOIN Fast_Moves f ON f.Name = bm.FastMove JOIN Charged_Moves c ON c.Name = bm.ChargedMove GROUP BY f.Name, f.DPS, c.Name, c.Damage, c.DPS, ((f.Cooldown * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Time), ((f.damage * CEIL(c.Energy_Required / f.Energy_Generated)) + c.Damage) ORDER BY f.Name, c.Name;
这个版本先把Beedrill的技能去重,避免后续关联时产生多余的重复项,适合数据量较大的场景。
内容的提问来源于stack exchange,提问作者Dan Plumbley
相关产品推荐
相关产品推荐

