Sql server 2012 计算管道和桩长度的运行成本

Sql server 2012 计算管道和桩长度的运行成本,sql-server-2012,Sql Server 2012,我在一家小公司工作,我们正试图摆脱Excel工作簿的库存控制。我以为我已经在纳赛尔的帮助下解决了这个问题,但我无能为力。这是我能进入一张桌子的东西,从那里我也需要得到它,使它看起来像下面的桌子 我的数据 预期产量 组的第一个记录将被视为期初余额。进料场的存货ID为1,出料场的存货ID为2。进入堆场的装载进尺总是有每英尺的装载成本,我可以计算出进尺的运行总成本。组的第一个记录很容易计算运行成本和每英尺运行成本。下一条记录变得更难计算。我需要将每英尺的平均运行成本向前移动到当有东西离开院子时每英尺的

我在一家小公司工作,我们正试图摆脱Excel工作簿的库存控制。我以为我已经在纳赛尔的帮助下解决了这个问题,但我无能为力。这是我能进入一张桌子的东西,从那里我也需要得到它,使它看起来像下面的桌子

我的数据

预期产量

组的第一个记录将被视为期初余额。进料场的存货ID为1,出料场的存货ID为2。进入堆场的装载进尺总是有每英尺的装载成本,我可以计算出进尺的运行总成本。组的第一个记录很容易计算运行成本和每英尺运行成本。下一条记录变得更难计算。我需要将每英尺的平均运行成本向前移动到当有东西离开院子时每英尺的负载成本,然后再次计算运行成本和每英尺的平均运行成本。希望这对某些人来说是有意义的,我们可以自动完成一些计算。谢谢你的帮助

下面是我发现的一个Oracle示例

SQL> select order_id
2       , volume
3       , price
4       , total_vol
5       , total_costs
6       , unit_costs
7    from ( select order_id
8                , volume
9                , price
10                , volume total_vol
11                , 0.0 total_costs
12                , 0.0 unit_costs
13                , row_number() over (order by order_id) rn
14             from costs
15            order by order_id
16         )
17   model
18         dimension by (order_id)
19         measures (volume, price, total_vol, total_costs, unit_costs)
20         rules iterate (4)
21         ( total_vol[any] = volume[cv()] + nvl(total_vol[cv()-1],0.0)
22         , total_costs[any]
23           = case SIGN(volume[cv()])
24             when -1 then total_vol[cv()] * nvl(unit_costs[cv()-1],0.0)
25             else volume[cv()] * price[cv()] + nvl(total_costs[cv()-1],0.0)
26             end
27         , unit_costs[any] = total_costs[cv()] / total_vol[cv()]
28         )
29   order by order_id
30  /

ORDER_ID     VOLUME      PRICE  TOTAL_VOL TOTAL_COSTS UNIT_COSTS
---------- ---------- ---------- ---------- ----------- ----------
     1       1000        100       1000      100000        100
     2       -500        110        500       50000        100
     3       1500         80       2000      170000         85
     4       -100        150       1900      161500         85
     5       -600        110       1300      110500         85
     6        700        105       2000      184000         92

选择6行。

让我先说三件事:

这当然不是最好的办法。有一条规则说,如果你需要一个while循环,那么你很可能是做错了什么。 我怀疑您的原始预期输出中存在一些计算错误,请检查计算,因为根据您的公式,我的计算值不同。 这个问题也可以被视为一种问题,但由于您提出了一个形式合理的问题,并进行了一些后续研究,我的答案如下。因此,无需向上投票,因为这对特定案例有帮助 现在谈谈解决方案:

我试图在一个格式良好的update语句中使用该语句的初始提示,但由于您只能在select或order by子句中使用一个窗口函数,即LAG,所以这将不起作用

简而言之,以下代码的作用是: 当可以计算每个记录时,它会计算每个记录的各种计算字段,并使用适当的函数更新表,然后移动到下一个记录。 有关更多信息,请参见代码中的注释。 Detritable是链接的SQLFiddle中可见的演示表。 有关小数点19,4的信息,请阅读此内容

输出包括示例数据和演示其工作原理的示例:

ID GrpID InOut LoadFt RunFt LoadCost RunCost LoadCostFt AvgRunCostFt 1 1 1 4549 4549 4503.51 4503.51 0.99 0.99 2 1 1 1523.22 6072.22 1964.9538 6468.4638 1.29 1.0653 3 1 2 -2491.73 3580.49 -2654.44 3814.0238 1.0653 1.0652 4 1 2 -96 3484.49 -102.2592 3711.7646 1.0652 1.0652 5 1 1 8471.68 11956.17 11945.0688 15656.8334 1.41 1.3095 6 1 2 -369 11587.17 -483.2055 15173.6279 1.3095 1.3095 7 2 1 1030.89 1030.89 5226.6123 5226.6123 5.07 5.07 8 2 1 314.17 1345.06 1806.4775 7033.0898 5.75 5.2288 9 2 1 239.56 1584.62 1509.228 8542.3178 6.3 5.3908 10 2 2 -554.46 1030.16 -2988.983 5553.3348 5.3908 5.3907 11 2 1 826.24 1856.4 4861.5962 10414.931 5.884 5.6103
如果您不清楚代码的某些部分,我可以用其他解释来更新。

我将在这里提示您这么久。如果其他人当时没有,您将在稍后写下答案。在您的数据中,所有输出记录的LoadCostft为0,但在预期数据中,所有记录都有一个值。是否有用于计算它们的特定计算?应该是上一行的RunCost/RunFt=AvgRunCostFt,其中InOut=2和GrpID=GrpID。我希望这有帮助,如果你需要更多的信息,请让我知道。谢谢你看这个。用会计术语来说,我想他们称之为移动平均库存法,相当于先进先出或后进先出。哇,我在经历这件事和观看卡尔加里-阿纳海姆季后赛曲棍球比赛之间左右为难。你能在SO之外得到联系和感谢吗?你可以通过贡献SO来感谢我:我投入了很多,在第二节课之后,我们什么都没输,你回答得再好不过了。结果不言而喻,我对你感激不尽。我会尽力帮忙,所以无论我在哪里,它都是一个值得支持的网站。你对我错误的自由手预期输出表很了解,而且很友好,而且仍然在努力地完成它。我认为你的回答是非常好的。
SQL> select order_id
2       , volume
3       , price
4       , total_vol
5       , total_costs
6       , unit_costs
7    from ( select order_id
8                , volume
9                , price
10                , volume total_vol
11                , 0.0 total_costs
12                , 0.0 unit_costs
13                , row_number() over (order by order_id) rn
14             from costs
15            order by order_id
16         )
17   model
18         dimension by (order_id)
19         measures (volume, price, total_vol, total_costs, unit_costs)
20         rules iterate (4)
21         ( total_vol[any] = volume[cv()] + nvl(total_vol[cv()-1],0.0)
22         , total_costs[any]
23           = case SIGN(volume[cv()])
24             when -1 then total_vol[cv()] * nvl(unit_costs[cv()-1],0.0)
25             else volume[cv()] * price[cv()] + nvl(total_costs[cv()-1],0.0)
26             end
27         , unit_costs[any] = total_costs[cv()] / total_vol[cv()]
28         )
29   order by order_id
30  /

ORDER_ID     VOLUME      PRICE  TOTAL_VOL TOTAL_COSTS UNIT_COSTS
---------- ---------- ---------- ---------- ----------- ----------
     1       1000        100       1000      100000        100
     2       -500        110        500       50000        100
     3       1500         80       2000      170000         85
     4       -100        150       1900      161500         85
     5       -600        110       1300      110500         85
     6        700        105       2000      184000         92
-- Our state and running variables
DECLARE @curId       INT = 0,
        @curGrpId    INT,
        @prevId      INT = 0,
        @prevGrpId   INT = 0,
        @LoadCostFt  DECIMAL(19, 4),
        @RunFt       DECIMAL(19, 4),
        @RunCost     DECIMAL(19, 4)

WHILE EXISTS (SELECT 1
                FROM TempTable
               WHERE DoneFlag = 0) -- DoneFlag is a bit column I added  to the table for calculation purposes, could also be called "IsCalced"
BEGIN
  SELECT top 1  -- top 1 here to get the next row based on the ID column
         @prevId   = @curId,
         @curId    = tmp.ID,
         @curGrpId = Grpid
    FROM TempTable tmp
   WHERE tmp.DoneFlag = 0
   ORDER BY tmp.GrpID, tmp.ID -- order by to ensure that we get everything from one GrpID first

   -- Calculate the LoadCostFt.
   -- It is either predetermined (if InOut = 1) or derived from the previous record's AvgRunCostFt (if InOut = 2)
   SELECT @LoadCostFt = CASE
                          WHEN tmp.INOUT = 2
                            THEN (lag(tmp.AvgRunCostFt, 1, 0.0) OVER (partition BY GrpId ORDER BY ID))
                          ELSE tmp.LoadCostFt
                        END
     FROM TempTable tmp
    WHERE tmp.ID IN (@curId, @prevId)
      AND tmp.GrpID = @curGrpId

   -- Calculate the LoadCost
   UPDATE TempTable
      SET LoadCost = LoadFt * @LoadCostFt
    WHERE Id = @curId

   -- Calculate the current RunFt and RunCost based on the current LoadFt and LoadCost plus the previous row's RunFt and RunCost
   SELECT @RunFt = (LoadFt + (lag(RunFt, 1, 0) OVER (partition BY GrpId ORDER BY ID))),
          @RunCost = (LoadCost + (lag(RunCost, 1, 0) OVER (partition BY GrpId ORDER BY ID)))
     FROM TempTable tmp
    WHERE tmp.ID IN (@curId, @prevId)
      AND tmp.GrpID = @curGrpId

   -- Set all our values, including the AvgRunCostFt calc
   UPDATE TempTable
      SET RunFt        = @RunFt,
          RunCost      = @RunCost,
          LoadCostFt   = @LoadCostFt,
          AvgRunCostFt = @RunCost / @RunFt,
          doneflag     = 1
    WHERE ID = @curId
END

SELECT ID, GrpID, InOut, LoadFt, RunFt, LoadCost,
       RunCost, LoadCostFt, AvgRunCostFt
  FROM TempTable
 ORDER BY GrpID, Id
ID GrpID InOut LoadFt RunFt LoadCost RunCost LoadCostFt AvgRunCostFt 1 1 1 4549 4549 4503.51 4503.51 0.99 0.99 2 1 1 1523.22 6072.22 1964.9538 6468.4638 1.29 1.0653 3 1 2 -2491.73 3580.49 -2654.44 3814.0238 1.0653 1.0652 4 1 2 -96 3484.49 -102.2592 3711.7646 1.0652 1.0652 5 1 1 8471.68 11956.17 11945.0688 15656.8334 1.41 1.3095 6 1 2 -369 11587.17 -483.2055 15173.6279 1.3095 1.3095 7 2 1 1030.89 1030.89 5226.6123 5226.6123 5.07 5.07 8 2 1 314.17 1345.06 1806.4775 7033.0898 5.75 5.2288 9 2 1 239.56 1584.62 1509.228 8542.3178 6.3 5.3908 10 2 2 -554.46 1030.16 -2988.983 5553.3348 5.3908 5.3907 11 2 1 826.24 1856.4 4861.5962 10414.931 5.884 5.6103