Sql 检索行,直到其数量总和小于@quantity

Sql 检索行,直到其数量总和小于@quantity,sql,tsql,stored-procedures,Sql,Tsql,Stored Procedures,我有一张桌子: 数据标识、名称、数量 我想编写一个存储过程来获取@quantity并检索它们的数量总和大于或等于@quantity的最小行 例如: id name quantity 1 a 3 2 b 1 3 c 7 4 d 2 对于@quantity=5,良好的结果可以是: 1, a, 3 2, b, 1 3, c, 7 或 或 等等。结果中的数量总和必须大于或等于@quantity,但我不需要额外

我有一张桌子: 数据标识、名称、数量

我想编写一个存储过程来获取@quantity并检索它们的数量总和大于或等于@quantity的最小行

例如:

id    name    quantity
1     a       3
2     b       1
3     c       7
4     d       2
对于@quantity=5,良好的结果可以是:

1, a, 3
2, b, 1
3, c, 7

等等。结果中的数量总和必须大于或等于@quantity,但我不需要额外的行。

编辑:添加解释

declare @goal int
set @goal = 5
;with numbered as
(
  -- this first query gives a sequential number to all records
  -- the biggest quantities are number 1,2,3 etc to the smallest quantities
  -- this ordering is because the minimum number of rows is most quickly
  -- achieved by combining the biggest quantities
  select id, name, quantity,
    row_number() over (order by quantity desc) rn
  from data
), cte as
( 
  -- this is a common table expression
  -- it starts off with the record with the biggest quantity
  select id, name, quantity, rn, sumsofar = quantity
  from numbered
  where rn = 1

  union all

  -- this is the recursive part
  -- "CTE" references the previous record in the loop
  select b.*, sumsofar + b.quantity
  from numbered b
  inner join cte a on b.rn = a.rn+1  -- add the next record (as ordered)
  -- continue the loop only if the goal is not yet reached
  where a.sumsofar < @goal
)
-- this finally selects all the records that have been collected to satisfy the @goal
select * from cte

-- NOTE: if @goal cannot be reached even with all records added up, this just
--       returns all records
这仅适用于SQL Server 2005+,因为它使用公共表表达式

这应该比下面的效果更好,但下面的也适用于2000年,或者你可以在2005/8年比较这两种方法,找出最适合你的方法

declare @goal int set @goal = 5

select c.*
from data c inner join 
(
    select top 1 * from
    (
        -- find the pivotal a.id on which the goal is reached
        select a.id, a.quantity, sum(b.quantity) s
        from data a
        -- this works on the b records on quantity desc, and id asc
        inner join data b
          on b.quantity < a.quantity
          or (b.quantity=a.quantity and b.id > a.id)
        group by a.id, a.quantity
        having sum(b.quantity) >= @goal
        union all
        -- if ALL records together cannot satisfy the GOAL
        -- we add a id=-1 record to mark this fact
        select -1, null, null
    ) oneonly
    -- find the min required, or return the fake -1 ID
    ORDER BY case when id=-1 then 1 else 0 end, s ASC, id ASC
) d
  on c.quantity > d.quantity
  or (c.quantity=d.quantity and c.id <= d.id)
  or d.id = -1   -- this matches all rows in C

请原谅我,但在中间例子中,数量之和等于5——那么这怎么可能呢?目前,问题的主体和标题似乎也不一致。如果您有一个特定的问题,请askI修改此代码以用于我的项目。但我有点问题。我需要对“金额”求和,哪种类型是小数点18,2。但是当执行时,我遇到了这样的错误:“递归查询cte的SumSoFar列中的锚和递归部分之间的类型不匹配。”对不起,我的英语水平很高
declare @goal int
set @goal = 5
;with numbered as
(
  -- this first query gives a sequential number to all records
  -- the biggest quantities are number 1,2,3 etc to the smallest quantities
  -- this ordering is because the minimum number of rows is most quickly
  -- achieved by combining the biggest quantities
  select id, name, quantity,
    row_number() over (order by quantity desc) rn
  from data
), cte as
( 
  -- this is a common table expression
  -- it starts off with the record with the biggest quantity
  select id, name, quantity, rn, sumsofar = quantity
  from numbered
  where rn = 1

  union all

  -- this is the recursive part
  -- "CTE" references the previous record in the loop
  select b.*, sumsofar + b.quantity
  from numbered b
  inner join cte a on b.rn = a.rn+1  -- add the next record (as ordered)
  -- continue the loop only if the goal is not yet reached
  where a.sumsofar < @goal
)
-- this finally selects all the records that have been collected to satisfy the @goal
select * from cte

-- NOTE: if @goal cannot be reached even with all records added up, this just
--       returns all records
declare @goal int set @goal = 5

select c.*
from data c inner join 
(
    select top 1 * from
    (
        -- find the pivotal a.id on which the goal is reached
        select a.id, a.quantity, sum(b.quantity) s
        from data a
        -- this works on the b records on quantity desc, and id asc
        inner join data b
          on b.quantity < a.quantity
          or (b.quantity=a.quantity and b.id > a.id)
        group by a.id, a.quantity
        having sum(b.quantity) >= @goal
        union all
        -- if ALL records together cannot satisfy the GOAL
        -- we add a id=-1 record to mark this fact
        select -1, null, null
    ) oneonly
    -- find the min required, or return the fake -1 ID
    ORDER BY case when id=-1 then 1 else 0 end, s ASC, id ASC
) d
  on c.quantity > d.quantity
  or (c.quantity=d.quantity and c.id <= d.id)
  or d.id = -1   -- this matches all rows in C