【问题标题】:SQL - Subtracting a depleting value from rowsSQL - 从行中减去一个耗尽的值
【发布时间】:2012-03-14 06:41:30
【问题描述】:

我有一种情况,我需要从一个表中获取“消耗的数量”,并将其应用于第二个表,该表有 1 行或更多行是“合并批次”的数量。我不知道如何更好地描述它,这是我从表格的角度来看的意思:

Table Pooled_Lots
----------------------------
Id  Pool    Lot Quantity
1   1       1   5
2   1       2   10
3   1       3   4
4   2       1   7
5   3       1   1
6   3       2   5

Table Pool_Consumption
----------------------------
Id  PoolId  QuantityConsumed
1   1       17
2   2       8
3   3       10

我需要一个来自 SQL 查询的结果行集,如下所示:

Pool    Lot Quantity    QuantityConsumed    RunningQuantity RemainingDemand SurplusOrDeficit
1       1   5           17                  0               12              NULL
1       2   10          17                  0               2               NULL
1       3   4           17                  2               0               2
2       1   7           8                   0               1               -1
3       1   1           10                  0               9               NULL
3       2   5           10                  0               4               -4

因此,Pool_Consumption.QuantityConsumed 需要是从 Pooled_Lots 的行中减去的“消耗值”,其中 Pool_Consumption.PoolId = Pooled_Lots.Pool。我不知道你会如何陈述这样的查询:

  • 如果不在最后一行,AmtConsumedFromLot = Quantity - QuantityConsumed if QuantityConsumed
  • 如果有更多行,QuantityConsumed = QuantityConsumed - Quantity
  • 循环直到最后一行
  • 如果最后一行,AmtConsumedFromLot = QuantityConsumed

假设 Id 是主键,目标 DB 是 SQL 2005。

编辑:由于人们宣称我“没有提供足够的信息,请关闭此”这里还有更多: Pool_Consumption 从中提取的 NO 设置批次,它需要从 all Pool_Consumption.PoolId = Pooled_Lots.Pool 的所有批次,直到 QuantityConsumed 完全耗尽或我减去 Pooled_Lots 行的最后一个子集,其中 Pool_Consumption.PoolId = Pooled_Lots.Pool

我不知道该怎么解释。这不是一个家庭作业问题,这不是一个虚构的“思想练习”。我需要帮助来弄清楚如何正确减去多行的 QuantityConsumed!

【问题讨论】:

  • 我不知道为什么人们会赞成这个问题,你有一些严重的数据粒度问题。 Pool_Consumption 表没有指定消耗的单位来自哪个批次。另外,我修正了一个错字。 -1
  • @JohnB 这是我目前面临的问题,尽可能简化,并且不泄露我工作中的机密数据。与其傲慢和宣称我在问一个不值得投票的愚蠢问题,也许您可​​以告诉我我需要在哪里添加“粒度”以使自己达到可以更轻松地产生所需输出的程度?
  • 这不是傲慢,如果您还没有阅读我的第一条评论,请阅读我的第一条评论(您需要 Pool_Consumption 表中的 Lot #)。另外,由于问题的质量,错别字太多(使其更难阅读),我对您投了反对票。
  • 我是 +1 中的一员。我同意@John 的语气过于严厉。这个问题很好,OP花了时间解释场景,并提出了一个有效的SQL问题。很公平,将Lot 添加到Pool_Consumption 会很有用。然而,我可以设想将消费与特定批次联系起来是不必要的甚至是未知的(因此记录不准确)的场景。业务规则似乎是先耗尽 PoolID 最低的池,然后级联。
  • 对不起,我觉得我很苛刻。我想我很不高兴,因为数学不正确,尽管如此,我仍然理解你问题的重点。此外,您想要的结果集的原始格式让我失望,因为基于您的 Pool_Consumption 架构是不可能实现的。我们花了 30 分钟解决您的问题,而不是制定解决方案。 :(

标签: sql sql-server sql-server-2005 tsql


【解决方案1】:

作为练习留给 OP:根据样本数据找出正确的结果并总结以下查询的结果:

-- Create some test data.
declare @Pooled_Lots as table ( Id int, Pool int, Lot int, Quantity int );
insert into @Pooled_Lots ( Id, Pool, Lot, Quantity ) values
  ( 1, 1, 1, 5 ), ( 2, 1, 2, 10 ), ( 3, 1, 3, 4 ),
  ( 4, 2, 1, 7 ),
  ( 5, 3, 1, 1 ), ( 6, 3, 2, 5 );
declare @Pool_Consumption as table ( Id int, Pool int, QuantityConsumed int );
insert into @Pool_Consumption ( Id, Pool, QuantityConsumed ) values
  ( 1, 1, 17 ), ( 2, 2, 8 ), ( 3, 3, 10 );

select * from @Pooled_Lots order by Pool, Lot;
select * from @Pool_Consumption order by Pool;

with Amos as (
  -- Start with Lot 1 for each Pool.
  select PL.Pool, PL.Lot, PL.Quantity, PC.QuantityConsumed,
    case
      when PC.QuantityConsumed is NULL then PL.Quantity
      when PL.Quantity >= PC.QuantityConsumed then PL.Quantity - PC.QuantityConsumed
      when PL.Quantity < PC.QuantityConsumed then 0
      end as RunningQuantity,
    case
      when PC.QuantityConsumed is NULL then 0
      when PL.Quantity >= PC.QuantityConsumed then 0
      when PL.Quantity < PC.QuantityConsumed then PC.QuantityConsumed - PL.Quantity
      end as RemainingDemand
    from @Pooled_Lots as PL left outer join
      @Pool_Consumption as PC on PC.Pool = PL.Pool
    where Lot = 1
  union all
  -- Add the next Lot for each Pool.
  select PL.Pool, PL.Lot, PL.Quantity, CTE.QuantityConsumed,
    case
      when CTE.RunningQuantity + PL.Quantity >= CTE.RemainingDemand then CTE.RunningQuantity + PL.Quantity - CTE.RemainingDemand
      when CTE.RunningQuantity + PL.Quantity < CTE.RemainingDemand then 0
      end,
    case
      when CTE.RunningQuantity + PL.Quantity >= CTE.RemainingDemand then 0
      when CTE.RunningQuantity + PL.Quantity < CTE.RemainingDemand then CTE.RemainingDemand - CTE.RunningQuantity - PL.Quantity
      end
    from Amos as CTE inner join
      @Pooled_Lots as PL on PL.Pool = CTE.Pool and PL.Lot = CTE.Lot + 1
  )
select *,
  case
    when Lot = ( select max( Lot ) from @Pooled_Lots where Pool = Amos.Pool ) then RunningQuantity - RemainingDemand
    else NULL end as SurplusOrDeficit
  from Amos
  order by Pool, Lot;

【讨论】:

  • 谢谢!这正是我想要的,甚至更多! (虽然我认为我会合并 RunningQuantity 和 RemainingDemand,因为它们很有用)
  • @TimLarson - 这看起来像是一个典型的仓库选货问题。我需要 13 个大腹便便的 Sneetches。拿起星腹 Sneetch 架子上的第一个盒子,看看有没有足够的。如果是这样,那就太好了。如果没有,请抓住下一个盒子。当你从架子的尽头掉下来时,你会拿起你的颜料和模板,开始寻找没有星星的 Sneetches。
【解决方案2】:

(基于问题的第 4 版,因为我的 WiFi 中断了很长一段时间)

(SELECT
  Pool,
  SUM(Quantity) as Pool_Quantity
FROM
  Pooled_Lots
GROUP BY
  Pool) as Pool_Quantity_Table

现在您有一个将池数量汇总为单个值的表。

现在是完整的查询:

SELECT
  Pool_Consumption.PoolID as Pool,
  Pool_Quantity_Table.Pool_Quantity as Quantity,
  Pool_Consumption.QuantityConsumed as AmtConsumedFromLot,
  (Pool_Quantity_Table.Pool_Quantity - Pool_Consumption.QuantityConsumed) as SurplusOrDefecit
FROM
  Pool_Consumption
INNER JOIN
  (SELECT
    Pool,
    SUM(Quantity) as Pool_Quantity
  FROM
    Pooled_Lots
  GROUP BY
    Pool) as Pool_Quantity_Table
ON (Pool_Consumption.PoolID = Pool_Quantity_Table.Pool);

【讨论】:

  • 感谢您抽出宝贵时间回答这个问题,JohnB。尽管在我目前的情况下将结果分成很多份更有帮助,但这个答案也有助于我理解我的问题的解决方案。对于我最初的最终结果表中的不准确之处,我深表歉意,我以为我已经仔细检查过了,直到您进行了修改才看到它。
  • 不客气。我很高兴您找到了解决问题的方法! :)
猜你喜欢
  • 1970-01-01
  • 2021-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-23
  • 1970-01-01
  • 2018-12-19
  • 1970-01-01
相关资源
最近更新 更多