我有一个供求表,如下所示,
Supply
Center1 1-Sep 500
Center1 1-Dec 1000
Demand
Center1 Req-1 1-Aug 300
Center1 Req-2 15-Aug 250
Center1 Req-3 1-Sep 1100
编写SQL代码以获取输出,如下所示,
预期的输出
Req_Dt Supply_Dt Units supplied
Center1 Req-1 1-Aug 1-Sep 300
Center1 Req-2 15-Aug 1-Sep 200
Center1 Req-2 15-Aug 1-Dec 50
Center1 Req-3 1-Sep 1-Dec 950
Center1 Req-3 1-Sep NULL 150
对于中心1,如果有请求1要求300个 1月8日,但自8月1日起没有可用的货源,因此直到获得货源,我们才能满足要求。接下来,仅在500个单位的9月1日收到货。因此,对于请求1,供应将在1月9日发生,并且将提供300个单位,因此仍然剩余200个。
现在,在8月15日的下一个请求2需要250个单位,并且由于在使用req-1之后,仍然需要9个1-Sep来满足剩余的200个单位的供应,因此我们通过陈述Req-2可以对请求的实现进行拆分在下一次供应到来时,在9月1日满足200个单位的需求,而在下一个供应期至12月1日仅满足50个需求。
尝试在存储过程中使用while循环,但处理数百万行时会花费更多时间。因此,需要编写函数或sql
预期的输出
Center Request Req_Dt Supply_Dt Units supplied
Center1 Req-1 1-Aug 1-Sep 300
Center1 Req-2 15-Aug 1-Sep 200
Center1 Req-2 15-Aug 1-Dec 50
Center1 Req-3 1-Sep 1-Dec 950
Center1 Req-3 1-Sep NULL 150
答案 0 :(得分:1)
这是循环遍历数据以获得所需结果的一种方法。
基本上,我已经建立了一系列处理表。一种用于一次过滤每个需求和供应行,另一种用于实际处理供应/需求行中事物的计数,这样做是为了使数据本身可以单独放置。最后,有一个动态创建的表可以自己生成输出。
循环基本上会继续进行,直到没有任何要过滤的内容为止,如果供应行或需求行中仍有任何未解决的内容,则该内容也将插入输出表中。每次通过时,都会查询当前需求和供应商处理程序表以查看是否需要添加新内容,然后在生成输出行后的循环结束时从处理程序表中删除等于或小于0的任何内容以确保仅一次处理一个供求行。
编辑: 我为中心添加了一个循环。这意味着具有多个中心的数据集现在将成功运行。
我还用更多行测试了该示例。有48个供应记录和80个需求记录,此查询在一秒钟内产生128个事务行,因此我怀疑您注意到的性能问题可能与中心循环有关,而不是查询性能本身。 让我知道您如何处理更新后的查询,如果有性能问题,我们可以调查原因。
请使用注释中提供的Center1和Center 2数据查看示例查询和数据,并将输出结果集粘贴到查询下方。
declare @Supply table (
Center nvarchar(20),
[Date] nvarchar(10),
Supply int
);
declare @Demand table (
Center nvarchar(20),
Requirement nvarchar(10),
[Date] nvarchar(10),
Demand int
);
insert @Supply (Center, Date, Supply)
values
('Center1', '1-Sep', 500),
('Center1', '1-Dec', 1000),
('Center2', '1-Oct', 700);
insert @Demand (Center, Requirement, Date, Demand)
values
('Center1', 'Req-1', '1-Aug', 300),
('Center1', 'Req-2', '15-Aug', 250),
('Center1', 'Req-3', '1-Sep', 1100),
('Center2', 'Req-1', '1-Sep', 500),
('Center2', 'Req-2', '1-Oct', 250);
declare @output table
( Center nvarchar(20),
Requirement nvarchar(10),
Req_Dt nvarchar(10),
Supply_Dt nvarchar(10),
Units_supplied int
);
declare @reqfilter table (
Requirement nvarchar(10),
Center nvarchar(20)
);
declare @supfilter table (
Date nvarchar(10),
Center nvarchar(20)
);
declare @req table (
Center nvarchar(20),
Requirement nvarchar(10),
Date nvarchar(10),
Demand int
);
declare @sup table (
Center nvarchar(20),
Date nvarchar(10),
Supply int
);
Declare @Centerfilter table (Center nvarchar(20));
insert @Centerfilter
select distinct Center from @Supply
union
select distinct Center from @Demand;
--select count(*) from @Supply as supply
--select count(*) from @Demand as demand
while exists (select 1 from @Centerfilter)
begin
insert @reqfilter
select requirement, c.Center from @Demand d inner join
(select top 1 Center from @Centerfilter order by Center) c
on d.Center=c.Center;
insert @supfilter
select date, s.Center from @Supply s inner join
(select top 1 Center from @Centerfilter order by Center) c
on s.Center=c.Center;
while exists (select 1 from @reqfilter outer apply @supfilter)
begin
if not exists (select 1 from @req)
begin
insert @req
select top 1 d.Center, d.Requirement, date, demand from
@Demand d inner join @reqfilter r on d.center=r.Center where d.Requirement in (select top 1 Requirement from @reqfilter order by Center, Requirement)
order by Center, parse(date as date);
delete @reqfilter from @reqfilter rq inner join @req r on rq.Requirement=r.Requirement and rq.Center=r.Center;
end
if not exists (select 1 from @sup)
begin
insert @sup
select top 1 s.Center, date, supply from
@Supply s inner join @Centerfilter c on s.Center=c.Center where date in (select top 1 Date from @supfilter order by Center, parse(date as date))
order by center, parse(date as date);
delete @supfilter from @supfilter s inner join @sup su on s.Date=su.date and s.Center=su.Center;
end
insert @output
select coalesce(d.center, s.center), requirement, d.date, s.date, case when supply>Demand then demand else supply end
from @req d inner join @sup s on d.Center=s.Center
update @req set demand=demand-o.Units_supplied
from @req r inner join (select top 1 Center, Requirement, Units_supplied from @output order by Center desc, parse(Req_Dt as date) desc, parse(Supply_Dt as date) desc) o on r.Center=o.Center and r.Requirement=o.Requirement;
update @sup set Supply=supply-units_supplied
from @sup s inner join @req r on s.Center=r.Center
inner join (select top 1 center, requirement, units_supplied from @output order by Center desc, parse(Req_Dt as date) desc, parse(Supply_Dt as date) desc)
o on s.Center=o.Center and r.Requirement=o.Requirement;
delete from @req where Demand<=0;
delete from @sup where Supply<=0;
end
if exists (select 1 from @req)
begin
insert @output
select center, requirement, Date, null, demand from @req;
end
if exists (select 1 from @sup)
begin
insert @output
select center, null, null, date, supply from @sup;
end
delete @Centerfilter where Center in (select top 1 Center from @Centerfilter order by Center);
delete from @reqfilter;
delete from @supfilter;
delete from @req;
delete from @sup;
end
select * from @output;
答案 1 :(得分:1)
DROP TABLE IF EXISTS #Supply
DROP TABLE IF EXISTS #Demand
SELECT * INTO #Supply FROM
(
SELECT CAST('09-01-2019' AS Date) AS dt, 'DC1' as DC, 500 AS KW
UNION
SELECT CAST('12-01-2019' AS Date), 'DC1', 1000
UNION
select CAST('10-01-2019' AS Date), 'DC2', 700
UNION
select CAST('10-01-2019' AS Date), 'DC3', 300
) Supply
SELECT * INTO #demand FROM
(
SELECT 'DC1' as DC, 'D1' as DemandId, 300 as KW, CAST('01-08-2019' AS Date) AS dt
UNION
SELECT 'DC1', 'D2', 250, CAST('08-15-2019' AS Date)
UNION
SELECT 'DC1', 'D3', 1100, CAST('08-15-2019' AS Date)
UNION
SELECT 'DC2', 'D1', 500, CAST('09-01-2019' AS Date)
UNION
SELECT 'DC2', 'D2', 250, CAST('09-15-2019' AS Date)
UNION
SELECT 'DC3', 'D1', 100, CAST('10-01-2019' AS Date)
UNION
SELECT 'DC3', 'D2', 200, CAST('11-01-2019' AS Date)
) Demand
DROP TABLE IF EXISTS #AllSupply
DROP TABLE IF EXISTS #AllDemand
DROP TABLE IF EXISTS #Final
SELECT RowID, DT, DC, KW, RunningTotalCurrent,
LAG(RunningTotalCurrent, 1,0) OVER(partition by DC Order by RowId) AS PriorRunning,
LEAD(RunningTotalCurrent, 1,0) OVER(partition by DC Order by RowId) AS NextRunning
into #AllSupply
FROM (SELECT S1.RowID, S1.dt, s1.KW, S1.DC , SUM(S1.KW) over (PARTITION BY s1.dc ORDER BY s1.dt rows UNBOUNDED preceding) AS RunningTotalCurrent
FROM (SELECT *, ROW_NUMBER() OVER(Partition By DC Order By dt ) AS RowID FROM #Supply) S1
) t
SELECT RowID, DemandId, DT, DC, KW, RunningTotalCurrent,LAG(RunningTotalCurrent, 1,0) OVER(partition by DC Order by RowId) AS PriorRunning,
LEAD(RunningTotalCurrent, 1,0) OVER( partition by DC Order by RowId) AS NextRunning
into #AllDemand
FROM (SELECT d1.RowID, d1.dt, d1.KW, d1.DC , d1.demandId, SUM(d1.KW) over (PARTITION BY d1.dc ORDER BY d1.dt rows UNBOUNDED preceding) AS RunningTotalCurrent
FROM (SELECT *, ROW_NUMBER() OVER(Partition By DC Order By dt, DemandId ) AS RowID FROM #Demand) d1) t
SELECT s.DC, D.DemandId, D.dt AS DemandDate, CASE WHEN s.dt < d.dt THEN d.dt ELSE ISNULL(S.dt,'11/11/2222') END AS SupplyDate, s.RunningTotalCurrent as SupplyRunningTotal,
d.RunningTotalCurrent as DemandRunningTotal, s.PriorRunning as SupplyPreviousTotal, d.PriorRunning as DemandPreviousTotal, s.kw as SupplyKW, d.kw as DemandKW,
CASE WHEN S.RunningTotalCurrent >= d.RunningTotalCurrent and s.PriorRunning = d.PriorRunning THEN d.kw
WHEN S.RunningTotalCurrent >= d.RunningTotalCurrent and s.PriorRunning > d.PriorRunning THEN d.kw - (s.PriorRunning - d.PriorRunning)
WHEN S.RunningTotalCurrent < d.RunningTotalCurrent AND s.PriorRunning = d.PriorRunning THEN s.kw
WHEN S.RunningTotalCurrent < d.RunningTotalCurrent AND s.PriorRunning > d.PriorRunning THEN d.kw - (s.PriorRunning - d.PriorRunning)
WHEN S.RunningTotalCurrent < d.RunningTotalCurrent AND s.PriorRunning < d.PriorRunning THEN S.RunningTotalCurrent - d.PriorRunning
WHEN S.RunningTotalCurrent = d.RunningTotalCurrent THEN d.kw
END AS Supply
INTO #Final
FROM #AllDemand D
LEFT JOIN #AllSupply S ON S.DC = D.DC
AND D.PriorRunning <= S.RunningTotalCurrent
AND D.RunningTotalCurrent >= S.PriorRunning
SELECT DC, DemandId, DemandDate, SupplyDate, Supply
FROM #Final
UNION
SELECT d.DC, d.DemandId, d.dt, '11/11/2222', d.kw - a.Supply
FROM (SELECT Dc, DemandId, SUM(Supply) AS Supply FROM #Final GROUP BY DC, DemandId) a
JOIN #demand d on a.DC= d.DC and a.DemandId = d.DemandId and d.kw > a.Supply