桶填充 SQL 查询 CTE
Bucket Filling SQL query CTE
我想从给定的输入 tables 中获得以下输出。
输入Table(要填充的桶)
ID | FullCapacity | CurrentAmount
---+--------------+--------------
B1 | 100 | 0
B2 | 50 | 0
B3 | 70 | 0
输入Table(填充Table)
ID | Filler
---+-------
F1 | 90
F2 | 70
F3 | 40
F4 | 20
输出 table 应该有下面显示的填充过程。
ID | FullCapacity | CurrentAmount
---+--------------+--------------
B1 | 100 | 90
B2 | 50 | 0
B3 | 70 | 0
---+--------------+--------------
B1 | 100 | 100
B2 | 50 | 50
B3 | 70 | 10
---+--------------+--------------
B1 | 100 | 100
B2 | 50 | 50
B3 | 70 | 50
---+--------------+--------------
B1 | 100 | 100
B2 | 50 | 50
B3 | 70 | 70
我正在尝试从填充物到桶一个一个地填充这个。我们可以不使用光标来做到这一点吗?
请注意我们可以有多种类型的桶,例如红色桶、蓝色桶和红色填充物、蓝色填充物。红色填料去红色桶,蓝色填料去蓝色等等。
谢谢
您需要做的只是累加和一些连接。因此,您可以在没有光标的情况下执行此操作。这个想法是使用累积连接,然后根据范围将每个填充记录分配给一个或多个存储桶。
对累积和使用 ANSI 标准语法:
select b.*, f.id,
(greatest(b.cumecap - b.fullcapacity, f.cumefiller - f.filler) -
least(b.cumecap, f.cumefiller)
) as amount_in_bucket
from (select b.*,
sum(b.fullcapacity) over (order by id) as cumecap
from buckets
) b join
(select f.*,
sum(f.filler) over (order by id) as cumefiller
from filler f
) f
on f.cumefiller - f.filler <= b.cumecap and
f.cumefiller >= b.cumecap - b.fullcapacity;
这会生成每个桶的映射以及桶中每个填充物的数量。
注意:它使用了函数 greatest()
和 least()
。如果函数不可用,这些很容易被 case
表达式替换。
您可以在 SQL Server 2008 中这样做:
declare @Buckets table (ID char(2), FullCapacity int)
declare @Filler table (ID char(2), Filler int)
insert into @Buckets
select 'B1', 100 union all
select 'B2', 50 union all
select 'B3', 70
insert into @Filler
select 'F1', 90 union all
select 'F2', 70 union all
select 'F3', 40 union all
select 'F4', 20
select
b.ID,
b.FullCapacity,
case
when f.TotalFill < b.RunningTotalCapacity then 0
when f.TotalFill > b.RunningTotalCapacity + b.FullCapacity then b.FullCapacity
else f.TotalFill - b.RunningTotalCapacity
end as CurrentAmount
from
(
select
ID,
Filler,
(
select sum(f2.Filler)
from @Filler as f2
where f2.ID <= f.ID
) as TotalFill
from @Filler as f
) as f
cross join
(
select
ID,
FullCapacity,
(
select isnull(sum(b2.FullCapacity), 0)
from @Buckets as b2
where b2.ID < b.ID
) as RunningTotalCapacity
from @Buckets as b
) as b
order by f.ID, b.ID
您可以像这样使用窗口函数来做到这一点:
SQL 服务器 2012+
declare @Buckets table (ID char(2), FullCapacity int)
declare @Filler table (ID char(2), Filler int)
insert into @Buckets values
('B1', 100),
('B2', 50),
('B3', 70)
insert into @Filler values
('F1', 90),
('F2', 70),
('F3', 40),
('F4', 20)
;with fillerCte as
(
select
ID,
Filler,
sum(Filler) over (order by ID) as TotalFill
from @Filler
),
BucketCte as
(
select
ID,
FullCapacity,
sum(FullCapacity) over (order by ID) - FullCapacity as RunningTotalCapacity
from @Buckets
)
select
b.ID,
b.FullCapacity,
case
when f.TotalFill < b.RunningTotalCapacity then 0
when f.TotalFill > b.RunningTotalCapacity + b.FullCapacity then b.FullCapacity
else f.TotalFill - b.RunningTotalCapacity
end as CurrentAmount
from fillerCte as f
cross join BucketCte as b
order by f.ID, b.ID
我想从给定的输入 tables 中获得以下输出。
输入Table(要填充的桶)
ID | FullCapacity | CurrentAmount
---+--------------+--------------
B1 | 100 | 0
B2 | 50 | 0
B3 | 70 | 0
输入Table(填充Table)
ID | Filler
---+-------
F1 | 90
F2 | 70
F3 | 40
F4 | 20
输出 table 应该有下面显示的填充过程。
ID | FullCapacity | CurrentAmount
---+--------------+--------------
B1 | 100 | 90
B2 | 50 | 0
B3 | 70 | 0
---+--------------+--------------
B1 | 100 | 100
B2 | 50 | 50
B3 | 70 | 10
---+--------------+--------------
B1 | 100 | 100
B2 | 50 | 50
B3 | 70 | 50
---+--------------+--------------
B1 | 100 | 100
B2 | 50 | 50
B3 | 70 | 70
我正在尝试从填充物到桶一个一个地填充这个。我们可以不使用光标来做到这一点吗?
请注意我们可以有多种类型的桶,例如红色桶、蓝色桶和红色填充物、蓝色填充物。红色填料去红色桶,蓝色填料去蓝色等等。
谢谢
您需要做的只是累加和一些连接。因此,您可以在没有光标的情况下执行此操作。这个想法是使用累积连接,然后根据范围将每个填充记录分配给一个或多个存储桶。
对累积和使用 ANSI 标准语法:
select b.*, f.id,
(greatest(b.cumecap - b.fullcapacity, f.cumefiller - f.filler) -
least(b.cumecap, f.cumefiller)
) as amount_in_bucket
from (select b.*,
sum(b.fullcapacity) over (order by id) as cumecap
from buckets
) b join
(select f.*,
sum(f.filler) over (order by id) as cumefiller
from filler f
) f
on f.cumefiller - f.filler <= b.cumecap and
f.cumefiller >= b.cumecap - b.fullcapacity;
这会生成每个桶的映射以及桶中每个填充物的数量。
注意:它使用了函数 greatest()
和 least()
。如果函数不可用,这些很容易被 case
表达式替换。
您可以在 SQL Server 2008 中这样做:
declare @Buckets table (ID char(2), FullCapacity int)
declare @Filler table (ID char(2), Filler int)
insert into @Buckets
select 'B1', 100 union all
select 'B2', 50 union all
select 'B3', 70
insert into @Filler
select 'F1', 90 union all
select 'F2', 70 union all
select 'F3', 40 union all
select 'F4', 20
select
b.ID,
b.FullCapacity,
case
when f.TotalFill < b.RunningTotalCapacity then 0
when f.TotalFill > b.RunningTotalCapacity + b.FullCapacity then b.FullCapacity
else f.TotalFill - b.RunningTotalCapacity
end as CurrentAmount
from
(
select
ID,
Filler,
(
select sum(f2.Filler)
from @Filler as f2
where f2.ID <= f.ID
) as TotalFill
from @Filler as f
) as f
cross join
(
select
ID,
FullCapacity,
(
select isnull(sum(b2.FullCapacity), 0)
from @Buckets as b2
where b2.ID < b.ID
) as RunningTotalCapacity
from @Buckets as b
) as b
order by f.ID, b.ID
您可以像这样使用窗口函数来做到这一点:
SQL 服务器 2012+
declare @Buckets table (ID char(2), FullCapacity int)
declare @Filler table (ID char(2), Filler int)
insert into @Buckets values
('B1', 100),
('B2', 50),
('B3', 70)
insert into @Filler values
('F1', 90),
('F2', 70),
('F3', 40),
('F4', 20)
;with fillerCte as
(
select
ID,
Filler,
sum(Filler) over (order by ID) as TotalFill
from @Filler
),
BucketCte as
(
select
ID,
FullCapacity,
sum(FullCapacity) over (order by ID) - FullCapacity as RunningTotalCapacity
from @Buckets
)
select
b.ID,
b.FullCapacity,
case
when f.TotalFill < b.RunningTotalCapacity then 0
when f.TotalFill > b.RunningTotalCapacity + b.FullCapacity then b.FullCapacity
else f.TotalFill - b.RunningTotalCapacity
end as CurrentAmount
from fillerCte as f
cross join BucketCte as b
order by f.ID, b.ID