我正在寻求使用存储过程基于另一个表的信息来更改表内容。为了说明我的观点(并躲避我生锈的英语技能),我创建了以下简化。
我有一张表格的片段数量
SELECT * FROM [dbo].[obtained_fragments] ->
fragment amount
22 42
76 7
101 31
128 4
177 22
212 6
和一个表格,其中列出了将这些片段与其他片段组合的所有可能组合。
SELECT * FROM [dbo].[possible_combinations] ->
fragment consists_of_f1 f1_amount_needed consists_of_f2 f2_amount_needed
1001 128 1 22 3
1004 151 1 101 12
1012 128 1 177 6
1047 212 1 76 4
我的目标是改变第一个表格,以便执行所有可能的片段组合,从而导致
SELECT * FROM [dbo].[obtained_fragments] ->
fragment amount
22 30
76 3
101 31
177 22
212 5
1001 4
1047 1
简而言之,基于[dbo]。[possible_combinations]将组合片段添加到表中,并减少所需片段的数量。从表中删除耗尽的碎片。
如何以简单的方式实现此片段转换?我开始编写一个while循环,检查是否有足够的片段可用,在for循环内部,通过片段编号进行交互。但是,我无法提出功能数量检查,并开始怀疑这是否可能以这种方式在T-SQL中实现。
代码不必非常高效,因为两个表总是小于200行。
请务必注意,创建哪种组合并不重要。
将[f1_amount_needed]的值始终设为1可能会派上用场。
使用iamdave的解决方案,只要我不触摸它就可以正常工作,我收到以下错误消息:
列名或提供的值数与表定义不匹配。
我几乎没有改变任何东西。是否有可能使用超过必要列的现有表而不是声明表(如iamdave所做的那样)会产生这种差异?
DECLARE @t TABLE(Binding_ID int, Exists_of_Binding_ID_2 int, Exists_of_Pieces_2 int, Binding1 int, Binding2 int);
WHILE 1=1
BEGIN
DELETE @t
INSERT INTO @t
SELECT TOP 1
k.Binding_ID
,k.Exists_of_Binding_ID_2
,k.Exists_of_Pieces_2
,g1.mat_Binding_ID AS Binding1
,g2.mat_Binding_ID AS Binding2
FROM [dbo].[vwCombiBinding] AS k
JOIN [leer].[sandbox5] AS g1
ON k.Exists_of_Binding_ID_1 = g1.mat_Binding_ID AND g1.Amount >= 1
JOIN [leer].[sandbox5] AS g2
ON k.Exists_of_Binding_ID_2 = g2.mat_Binding_ID AND g2.Amount >= k.Exists_of_Pieces_2
ORDER BY k.Binding_ID
IF (SELECT COUNT(1) FROM @t) = 1
BEGIN
UPDATE g
SET Amount = g.Amount +1
FROM [leer].[sandbox5] AS g
JOIN @t AS t
ON g.mat_Binding_ID = t.Binding_ID
INSERT INTO [leer].[sandbox5]
SELECT
t.Binding_ID
,1
FROM @t AS t
WHERE NOT EXISTS (SELECT NULL FROM [leer].[sandbox5] AS g WHERE g.mat_Binding_ID = t.Binding_ID);
UPDATE g
SET Amount = g.Amount - 1
FROM [leer].[sandbox5] AS g
JOIN @t AS t
ON g.mat_Binding_ID = t.Binding1
UPDATE g
SET Amount = g.Amount - t.Exists_of_Pieces_2
FROM [leer].[sandbox5] AS g
JOIN @t AS t
ON g.mat_Binding_ID = t.Binding2
END
ELSE
BREAK
END
SELECT * FROM [leer].[sandbox5]
答案 0 :(得分:1)
您可以使用包含多个语句的while
循环来处理迭代数据更新。由于您需要根据每次迭代重新评估数据进行更改,因此 将在某种循环中完成:
declare @f table(fragment int,amount int);
insert into @f values (22 ,42),(76 ,7 ),(101,31),(128,4 ),(177,22),(212,6 );
declare @c table(fragment int,consists_of_f1 int,f1_amount_needed int,consists_of_f2 int,f2_amount_needed int);
insert into @c values (1001,128,1,22,3),(1004,151,1,101,12),(1012,128,1,177,6),(1047,212,1,76,4);
declare @t table(fragment int,consists_of_f2 int,f2_amount_needed int,fragment1 int,fragment2 int);
while 1 = 1
begin
-- Clear out staging area
delete @t;
-- Populate with the latest possible combination
insert into @t
select top 1 c.fragment
,c.consists_of_f2
,c.f2_amount_needed
,f1.fragment as fragment1
,f2.fragment as fragment2
from @c as c
join @f as f1
on c.consists_of_f1 = f1.fragment
and f1.amount >= 1
join @f as f2
on c.consists_of_f2 = f2.fragment
and f2.amount >= c.f2_amount_needed
order by c.fragment;
-- Update fragments table if a new combination can be made
if (select count(1) from @t) = 1
begin
-- Update if additional fragment
update f
set amount = f.amount + 1
from @f as f
join @t as t
on f.fragment = t.fragment;
-- Insert if a new fragment
insert into @f
select t.fragment
,1
from @t as t
where not exists(select null
from @f as f
where f.fragment = t.fragment
);
-- Update fragment1 amounts
update f
set amount = f.amount - 1
from @f as f
join @t as t
on f.fragment = t.fragment1;
-- Update fragment2 amounts
update f
set amount = f.amount - t.f2_amount_needed
from @f as f
join @t as t
on f.fragment = t.fragment2;
end
else -- If no new combinations possible, break the loop
break
end;
select *
from @f;
输出:
+----------+--------+
| fragment | amount |
+----------+--------+
| 22 | 30 |
| 76 | 3 |
| 101 | 31 |
| 128 | 0 |
| 177 | 22 |
| 212 | 5 |
| 1001 | 4 |
| 1047 | 1 |
+----------+--------+