如何筛选存在子项组合面积和等于指定值的建筑?
解决建筑公寓面积组合和的SQL筛选问题
要实现任意数量公寓面积组合和的筛选,仅靠MIN()和SUM()只能覆盖单套和总面积的情况,中间的组合需要用**递归CTE(公共表表达式)**来生成所有可能的子集和,再匹配目标条件。
原SQL的问题
你的现有SQL存在两处明显问题:
- 子查询中表别名错误:
lot.id_building应该是a2.id_building - 仅覆盖了单套最小面积和总面积,完全没处理中间的组合和场景
解决方案:递归CTE生成所有组合和
以下是针对目标范围(比如399-401㎡)的完整SQL,会自动生成每个建筑下所有可能的公寓面积组合和,再筛选符合条件的建筑:
WITH RECURSIVE apartment_sums AS ( -- 初始步骤:单套公寓的面积 SELECT a.id_building, a.surface AS total_surface, CAST(a.id AS VARCHAR) AS used_apartments -- 记录已选公寓ID,避免重复组合 FROM appartment a UNION ALL -- 递归步骤:累加其他未选的公寓面积 SELECT s.id_building, s.total_surface + a.surface AS total_surface, s.used_apartments || ',' || a.id AS used_apartments FROM apartment_sums s JOIN appartment a ON a.id_building = s.id_building AND a.id > (SELECT MAX(CAST(unnest(string_to_array(s.used_apartments, ',')) AS INT))) -- 确保只加未选过的公寓,避免重复组合 ) SELECT DISTINCT b.* FROM building b WHERE EXISTS ( SELECT 1 FROM apartment_sums s WHERE s.id_building = b.id AND s.total_surface BETWEEN 399 AND 401 -- 匹配目标面积范围 );
代码解释
- 递归CTE的初始部分:先取出每个公寓的单套面积,作为基础组合。
- 递归部分:不断将已有组合和与同建筑下未被选中的公寓面积累加,生成新的组合和,同时记录已用公寓ID防止重复计算(比如避免把“公寓1+公寓2”和“公寓2+公寓1”当成两个不同组合)。
- 最终筛选:通过
EXISTS判断该建筑是否存在符合目标范围的组合和,返回对应的建筑信息。
适配你的示例场景
如果建筑A有3套200㎡的公寓,递归CTE会生成以下组合和:
- 200(单套)
- 400(任意两套之和)
- 600(三套总和)
当目标范围是399-401时,就会匹配到400㎡的组合,从而检索到该建筑。
注意事项
- 如果公寓数量较多,递归可能会产生大量数据,建议在实际使用时添加建筑ID的过滤条件减少计算量。
- 不同数据库的字符串处理函数可能有差异(比如PostgreSQL用
string_to_array,MySQL用SUBSTRING_INDEX),需要根据你使用的数据库调整递归部分的ID判断逻辑。
内容的提问来源于stack exchange,提问作者Nico
相关产品推荐
相关产品推荐

