【问题标题】:sql server : select rows who's sum matches a value [duplicate]sql server:选择总和与值匹配的行[重复]
【发布时间】:2014-01-28 00:39:25
【问题描述】:

这里是表T :-

id  num
-------
 1  50
 2  20
 3  90
 4  40
 5  10
 6  60
 7  30
 8  100
 9  70
10  80

以下是虚构的 sql

select *
from T
where sum(num) = '150'

预期结果是:-

(A)

id  num
-------
 1  50
 8  100

(B)

id  num
-------
 2  20
 7  30
 8  100

(C)

id  num
-------
 4  40
 5  10
 8  100

'A' 案例是最优选的!

我知道这种情况与组合有关。

在现实世界中 - 客户从商店获取商品,并且由于他与商店之间的协议,他每周五付款。付款金额不是项目的确切总数 例如:他得到了 5 本书 50 欧元(= 250 欧元),周五他带来了 150 欧元,所以前 3 本书是完美的匹配 - 3 * 50 = 150。我需要找到这 3 本书的 ID!

任何帮助将不胜感激!

【问题讨论】:

  • 或者(3,90);(6,60),或者(9,70);(10,80),为什么第一个选项是“最喜欢的”?
  • 我认为这个问题需要迭代的方法,这不是SQL的强项。
  • @Lamak 第一个选项是“最喜欢的”,因为它的行数较少。但它是可选的
  • 正如@Lamak 所说:3 (90) and 6 (60)9 (70) and 10(80) 之间的组合也会产生 2 行。

标签: sql sql-server sql-server-2012 subset-sum


【解决方案1】:

您可以在 MSSQL 中使用递归查询来解决这个问题。

SQLFiddle demo

第一个递归查询构建一个累积和 ItemsCount 排序的最终结果中,因此您将首先获得首选组(项目数最少)。

WITH CTE as
( SELECT id,num,
         id as Grp,
         0 as parent,
         num as CSum,
         1 as cnt,
         CAST(id as Varchar(MAX)) as path
     from T where num<=150
  UNION all
  SELECT t.id,t.num,
         CTE.Grp as Grp, 
         CTE.id as parent,
         T.num+CTE.CSum as CSum,
         CTE.cnt+1 as cnt,
         CTE.path+','+CAST(t.id as Varchar(MAX)) as path
    from T 
  JOIN CTE on T.num+CTE.CSum<=150 
             and CTE.id<T.id 
),
BACK_CTE as
(select CTE.id,CTE.num,CTE.grp, 
         CTE.path ,CTE.cnt as cnt,
         CTE.parent,CSum 
    from CTE where CTE.CSum=150
  union all
  select CTE.id,CTE.num,CTE.grp,
         BACK_CTE.path,BACK_CTE.cnt, 
         CTE.parent,CTE.CSum 
   from CTE
   JOIN BACK_CTE on CTE.id=BACK_CTE.parent 
              and CTE.Grp=BACK_CTE.Grp
              and BACK_CTE.CSum-BACK_CTE.num=CTE.CSum
) 
select id,NUM,path, cnt as ItemsCount   from BACK_CTE order by cnt,path,Id

【讨论】:

  • 完美!第一行是预期的结果!谢谢。
【解决方案2】:

如果你把你的问题限制在“哪个两个个数加起来一个值”,解决方法如下:

SELECT t1.id, t1.num, t2.id,t2.num
FROM T t1 
INNER JOIN T t2
ON t1.id < t2.id
WHERE t1.num + t2.num  = 150

如果您还想要三个或更多数字的结果,您可以通过使用上述查询作为递归 SQL 的基础来实现。不要忘记指定最大递归深度!

【讨论】:

  • 我对递归了解不多。我将阅读有关递归的更多信息以尝试您的方法。
【解决方案3】:

要查找客户正在支付的书籍的 ID,您需要与客户有一张桌子,另外还有一张用于存储客户的订单以及他购买的产品。

否则无法知道付款是指什么产品。

【讨论】:

  • 当然有一个客户ID,我只是将问题最小化,所以表格只包含一个客户的信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-12
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
  • 2018-02-03
  • 1970-01-01
  • 2022-01-15
相关资源
最近更新 更多