替代方案:Sql - SELECT行,直到行的总和为某个值

时间:2018-03-02 14:01:53

标签: sql sql-server sql-server-2016

我的问题与我之前发布的问题非常类似: Sql - SELECT rows until the sum of a row is a certain value

总结一下,我需要返回行,直到达到一定的总和,但这次的不同之处在于,我需要找到最适合这个总和的,我的意思是,它没有'必须是顺序的。例如:

我们说我有5张来自客户1的未付款收据:

Receipt_id: 1 | Amount: 110€
Receipt_id: 2 | Amount: 110€
Receipt_id: 3 | Amount: 130€
Receipt_id: 4 | Amount: 110€
Receipt_id: 5 | Amount: 190€

因此,客户1应该向我支付220欧元。

现在我需要选择收据,直到这个220欧元的金额得到满足,它可能是一个直接的顺序,如(收据1 +收据2)或不是特定的顺序,如(收据1 +收据4) ,任何这些情况都适合。

我正在使用SQL Server 2016。

任何其他问题,请随时提出。

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

此查询应解决此问题。

  

这是一个非常危险的查询(包含递归CTE),所以请小心!

您可以在此处找到一些文档:https://www.essentialsql.com/recursive-ctes-explained/

  WITH the_data as (
      SELECT * 
      FROM (
           VALUES (1, 1, 110),(1, 2,110),(1, 3,130),(1, 4,110),(1, 5,190),
           (2, 1, 10),(2, 2,20),(2, 3,200),(2, 4,190)
             ) t (user_id, receipt_id, amount)
  ), permutation /* recursive used here */ as (
      SELECT 
          user_id,
          amount as sum_amount, 
          CAST(receipt_id as varchar(max)) as visited_receipt_id,
          receipt_id as max_receipt_id,
          1 as i
      FROM the_data
      WHERE amount > 0 -- remove empty amount

      UNION ALL 

      SELECT 
          the_data.user_id, 
          sum_amount + amount as sum_amount,
          CAST(concat(visited_receipt_id, ',', CAST(receipt_id as varchar))as varchar(max)) as visited_receipt_id,
          receipt_id as max_receipt_id , 
          i + 1 
      FROM the_data
      JOIN permutation
        ON the_data.user_id = permutation.user_id
      WHERE i < 1000 -- max 1000 loops, means any permutation with less than 1000 different receipts 
        and receipt_id > max_receipt_id -- in order that sum in komutatif , we can check the sum in any unique order ( here we take the order of the reciept_id in fact we do not produce any duplicates )  
        -- AND sum_amount + amount <= 220 -- ignore everything that is bigger than the expected value (optional)
  ) 
  SELECT * 
  FROM permutation
  WHERE sum_amount = 220

为了每个user_id只选择一个组合,用

替换上一个查询的最后三行
SELECT *
FROM (
    SELECT *, row_number() OVER (partition by user_id order by random() ) as r  
    FROM permutation
    WHERE sum_amount = 220
) as t
WHERE r = 1

答案 1 :(得分:0)

如果您的目标只是为了达到您的价值而只收取2个收据,这可能是一个解决方案:

DECLARE @TARGET   INT = 220 --SET YOUR TARGET
      , @DIFF     INT
      , @FIRSTVAL INT

SET @FIRSTVAL = (
         SELECT TOP 1 AMOUNT
         FROM myRECEIPTS
         ORDER BY RECEIPT_ID ASC
)

SELECT   TOP 1 *
FROM     myRECEIPTS
WHERE    AMOUNT = @TARGET - @FIRSTVAL
ORDER BY RECEIPT_ID ASC

答案 2 :(得分:0)

此代码将执行此操作:

    declare @sum1 int
    declare @numrows int
    set @numrows= 1
    set @sum1 =0
    while (@sum1 < 10)
    begin
     select top (@numrows) @sum1=sum(sum1) from receipts
     set  @numrows +=1
     end
  select top(@numrows) * from receipts