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

问题描述 投票:-1回答:3

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

总结一下,我需要返回行,直到达到某个总和,但这次的差异是,我需要找到最适合这个总和,我的意思是,它不必是顺序的。例如:

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

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。

任何其他问题,随时问。

在此先感谢您的帮助。

sql sql-server sql-server-2016
3个回答
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

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

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
© www.soinside.com 2019 - 2024. All rights reserved.