在T-SQL中挣扎着逻辑

时间:2015-03-24 14:37:55

标签: sql sql-server tsql sql-server-2008-r2

我需要T-SQL的一些帮助。

我不能使用循环,游标等。这是因为我需要高性能。

如果你能帮助我,我将非常感激。

这是我的问题:

我有一个名为__tt_Freight_Product的表,其中包含以下列:

dt_reference_date, id_contract, qtt_terminal_loaded

一个名为Product的表,其中包含以下列:

dt_reference_date, id_contract, id_fixing, qtt_fixing, qtt_terminal

它们之间没有外键,但id_contractdt_reference_date应该是相同的。

__tt_Freight_Product中的示例数据:

('2015-02-25', '0000006-t12', 200000)
('2015-02-26', '0000006-t12', 200000)
('2015-02-28', '0000006-t12', 100000)

该数据意味着在'2015-02-25'的终端合约'0000006-t12'上加载了200,000吨,等等

Product中的示例数据:

('2015-02-24', '0000006-t12', 1, 300000, 0)
('2015-02-25', '0000006-t12', 1, 300000, 0)
('2015-02-26', '0000006-t12', 1, 300000, 0)
('2015-02-27', '0000006-t12', 1, 300000, 0)
('2015-02-28', '0000006-t12', 1, 300000, 0)
('2015-02-29', '0000006-t12', 1, 300000, 0)
('2015-02-24', '0000006-t12', 2, 200000, 0)
('2015-02-25', '0000006-t12', 2, 200000, 0)
('2015-02-26', '0000006-t12', 2, 200000, 0)
('2015-02-27', '0000006-t12', 2, 200000, 0)
('2015-02-28', '0000006-t12', 2, 200000, 0)
('2015-02-29', '0000006-t12', 2, 200000, 0)

我需要完成的工作是按__tt_Freight_ProductProduct上的已加载卷拆分为dt_reference_date/id_contract/id_fixing表。该拆分卷将在Product表上更新。

我们必须按“id_fixing”划分音量。

因此,考虑到__tt_Freight_Product上的示例数据,我们将更新:

dt_reference_date:'2015-02-24'

由于装载货物只是第25次

,因此不会更新任何内容

dt_reference_date:'2015-02-25'

id_fixing“1”的qtt_terminal将更新为200,000

id_fixing“2”的qtt_terminal不会改变

dt_reference_date:'2015-02-26'

id_fixing“1”的qtt_terminal将更新为300,000

id_fixing“2”的qtt_terminal将更新为100,000

dt_reference_date:'2015-02-27'

id_fixing“1”的qtt_terminal将更新为300,000,因为我们前一天有货物,27日没有装货或考虑到我们已经有id_fixing'1'“已完全分配”< / p>

id_fixing“2”的qtt_terminal将更新为100,000,因为我们前一天有货物,27日没有装货

dt_reference_date:'2015-02-28'

id_fixing“1”的qtt_terminal将更新为300,000,因为我们前一天有货物,27日没有装货或考虑到我们已经有id_fixing'1'“已完全分配”< / p>

id_fixing“2”的qtt_terminal将更新为200,000

dt_reference_date:'2015-02-29'

id_fixing“1”的qtt_terminal将更新为300,000,因为我们前一天有货物,29日没有装货或考虑到我们已经有id_fixing'1'“全部分配”< / p>

id_fixing“2”的qtt_terminal将更新为200,000,因为我们前一天有货物并且29日没有装货或考虑到我们已经有id_fixing'2'“已完全分配”< / p>

修改

我必须得到__tt_Freight_Product中的值[qtt_terminal_loaded]并在表Product qtt_terminal上“分配”它。但是,我必须按照它们出现的顺序将__tt_Freight_Product.qtt_terminal_loaded分发到一个或多个“id_fixing”中(id_fixing = 1和2)。

这样,就像在示例数据中一样,在25日,我们有qtt_terminal_loaded等于200,000。所以,这200,00,是我能够分配到多个id_fixing的数量。但是,id_fixing = 1,从qtt_terminal_loaded(这是由“qtt_fixing”列确定的“余额”300,00“接收”.qtt_terminal,我想要更新的列,不能超过qtt_fixing从来没有。那样,26日,如果我们将之前的qtt_terminal_loaded相加,我们就得到400,00。但是第一次id_fixing只有300,000。所以,从那天开始,我开始分配到id_fixing = 2.在这种情况下,100,000那天。

我清楚了吗?我正尽力解释。

结束编辑

包含样本输出的图片: enter image description here

包含表创建和示例数据的脚本:

-- CREATE sample "__tt_Freight_Product"
IF object_id('tempdb..#__tt_Freight_Product') IS NOT NULL
BEGIN
    DROP TABLE #__tt_Freight_Product;
END;

SELECT  a.dt_reference_date,
        a.id_contract,
        a.qtt_terminal_loaded
INTO    #__tt_Freight_Product
FROM    ( VALUES ( '2015-02-25', '0000006-t12', 200000),
        ( '2015-02-26', '0000006-t12', 200000),
        ( '2015-02-28', '0000006-t12', 100000) ) a ( dt_reference_date, id_contract, qtt_terminal_loaded );

-- CREATE sample "Product"
IF object_id('tempdb..#Product') IS NOT NULL
BEGIN
    DROP TABLE #Product;
END;

SELECT  a.dt_reference_date,
        a.id_contract,
        a.id_fixing,
        a.qtt_fixing,
        a.qtt_terminal
INTO    #Product
FROM    ( VALUES ( '2015-02-24', '0000006-t12', 1, 300000, 0),
        ( '2015-02-25', '0000006-t12', 1, 300000, 0),
        ( '2015-02-26', '0000006-t12', 1, 300000, 0),
        ( '2015-02-27', '0000006-t12', 1, 300000, 0),
        ( '2015-02-28', '0000006-t12', 1, 300000, 0),
        ( '2015-02-29', '0000006-t12', 1, 300000, 0),
        ( '2015-02-24', '0000006-t12', 2, 200000, 0),
        ( '2015-02-25', '0000006-t12', 2, 200000, 0),
        ( '2015-02-26', '0000006-t12', 2, 200000, 0),
        ( '2015-02-27', '0000006-t12', 2, 200000, 0),
        ( '2015-02-28', '0000006-t12', 2, 200000, 0),
        ( '2015-02-29', '0000006-t12', 2, 200000, 0) ) a ( dt_reference_date, id_contract, id_fixing, qtt_fixing, qtt_terminal );

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

您的数据模型中似乎存在一些非规范化。对于所有出现的相同id_contract和id_fixing,似乎重复相同的qtt_fixing值,对吧?假设有保证,这是一个可能的解决方案:

with f as
(
  select *,
    sum(qtt_terminal_loaded) over(partition by id_contract
                                  order by dt_reference_date
                                  rows unbounded preceding) as runsum
  from #__tt_freight_product
),
p as
(
  select *,
    sum(qtt_fixing) over(partition by id_contract, dt_reference_date
                         order by id_fixing
                         rows unbounded preceding) as runsum
  from #product
)
update p
  set qtt_terminal =
    case
      when f.runsum >= p.runsum then p.qtt_fixing
      when p.runsum - p.qtt_fixing < f.runsum then f.runsum - (p.runsum - p.qtt_fixing)
      else 0
    end
from p
  outer apply (select top (1) *
               from f
               where f.id_contract = p.id_contract
                 and f.dt_reference_date <= p.dt_reference_date
               order by f.dt_reference_date desc) as f;

select *
from #product;

请注意,该解决方案根本没有优化。我提供它只是为了你可以学习逻辑。需要更多步骤来优化它,例如将中间结果存储在临时表中并对其进行索引。 此外,此解决方案使用带有框架的聚合窗口函数 - 这是SQL Server 2012中引入的一项功能。如果您使用旧版本,则最好使用迭代解决方案。

干杯, 伊茨克