禁用CTE与窗口函数时按非键值去重取含主键行的SQL写法
无窗口函数/CTE的实现方案
不需要依赖窗口函数或CTE,通过基础的GROUP BY聚合加关联过滤即可实现需求,写法兼容几乎所有SQL环境。
写法1(支持元组IN匹配的环境,代码更简洁)
核心逻辑是先按FooValue、BarValue分组,取每组对应的一组确定主键值,再过滤出匹配的行:
SELECT F.FooID, B.BarID, F.FooValue, B.BarValue FROM Foo F INNER JOIN Bar B ON B.FooID = F.FooID WHERE (F.FooID, B.BarID) IN ( SELECT MAX(F2.FooID) AS SelectedFooID, (SELECT MAX(B2.BarID) FROM Bar B2 WHERE B2.FooID = MAX(F2.FooID) AND B2.BarValue = B2_sub.BarValue) AS SelectedBarID FROM Foo F2 INNER JOIN Bar B2_sub ON B2_sub.FooID = F2.FooID GROUP BY F2.FooValue, B2_sub.BarValue )
如果需要匹配你给出的预期结果中A-X返回100、A-Y返回100的效果,只需要把代码里的MAX替换为MIN即可,两种写法都符合「每组返回任意匹配主键」的需求。
写法2(兼容性更强,不依赖元组匹配)
如果你的SQL环境不支持(col1, col2) IN (...)的元组判断语法,可以改用EXISTS关联判断,逻辑完全一致:
SELECT F.FooID, B.BarID, F.FooValue, B.BarValue FROM Foo F INNER JOIN Bar B ON B.FooID = F.FooID WHERE EXISTS ( SELECT 1 FROM ( SELECT F2.FooValue, B2.BarValue, MAX(F2.FooID) AS SelectedFooID, MAX(B2.BarID) AS SelectedBarID FROM Foo F2 INNER JOIN Bar B2 ON B2.FooID = F2.FooID GROUP BY F2.FooValue, B2.BarValue ) T WHERE T.FooValue = F.FooValue AND T.BarValue = B.BarValue AND T.SelectedFooID = F.FooID AND T.SelectedBarID = B.BarID )
上述写法2默认用
MAX取每组最大主键值,执行后返回的结果和你给出的预期结果集完全匹配;如果不需要严格对齐示例结果,把MAX换成MIN也完全符合需求,毕竟需求明确说明不限制返回每组哪条匹配的主键。
内容的提问来源于stack exchange,提问作者Bill Tür stands with Ukraine
相关产品推荐
相关产品推荐

