我需要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_contract
和dt_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_Product
将Product
上的已加载卷拆分为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那天。
我清楚了吗?我正尽力解释。结束编辑
包含样本输出的图片:
包含表创建和示例数据的脚本:
-- 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 );
有什么想法吗?
答案 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中引入的一项功能。如果您使用旧版本,则最好使用迭代解决方案。
干杯, 伊茨克