我遇到了一个SQL挑战。我的情况是这样的。
我有一个名为#Balance的表,其中我有历史数据(总是versionid = 0)和预测数据(增加的版本ID> 0)。
每个月都会产生新的预后。
因此,在2017年12月,我们有截至2017年11月的历史数据,但预计将于2017年12月和未来几个月创建预测153。
在2018年1月,我们有截至2017年12月的历史数据,并且从2018年1月开始新的预后,所以它会继续。
但麻烦来自报道。因为每个预后都必须包括所有历史月份,直至预测开始月份。
下面你看一个例子。
版本表已简化,它有更多行,因此是平衡。我想要的是最终结果,其中包含历史数据,但也会在预测开始月份之前为所有预测增加历史记录。
SQL代码应该是通用的,因此它可以为更多版本ID生成结果表。我需要使用来自版本的historyTo和来自Balance的(AYear * 100 + APer)来查找结果。
有人可以帮助我吗?
谢谢
关心Geir
Version
x------------x------------------------x
| Id | Name | HistoryTo |
x------------x------------------------x
| 0 | History | 200701 |
| 153 | Nov 2017 | 201711 |
| 154 | Des 2017 | 201712 |
x------------x-----------x------------x
Balance
x------------x--------------------x---------x
| VersionId | AYear | APer | Amount |
x------------x--------------------x---------x
| 0 | 2017 | 10 | 29327 |
| 0 | 2017 | 11 | 351 |
| 0 | 2017 | 12 | 6530 |
| 154 | 2018 | 1 | 25000 |
| 154 | 2018 | 2 | 39136 |
| 154 | 2018 | 3 | 20000 |
| 153 | 2017 | 12 | 3000 |
| 153 | 2017 | 1 | 47000 |
| 153 | 2017 | 2 | 35000 |
x------------x---------x----------x---------|
Result
x------------x--------------------x---------x
| VersionId | AYear | APer | Amount |
x------------x--------------------x---------x
| 0 | 2017 | 10 | 29327 |
| 0 | 2017 | 11 | 351 |
| 0 | 2017 | 12 | 6530 |
| 154 | 2017 | 10 | 29327 |
| 154 | 2017 | 11 | 351 |
| 154 | 2017 | 12 | 6530 |
| 154 | 2018 | 1 | 25000 |
| 154 | 2018 | 2 | 39136 |
| 154 | 2018 | 3 | 20000 |
| 153 | 2017 | 10 | 29327 |
| 153 | 2017 | 11 | 351 |
| 153 | 2017 | 12 | 3000 |
| 153 | 2017 | 1 | 47000 |
| 153 | 2017 | 2 | 35000 |
x------------x---------x---------x----------|
create table #Version (
Id int
, [Name] varchar(100)
, HistoryTo int
, constraint PK_Version primary key (Id)
)
GO
create table #Balance (
Id int identity(1,1)
, VersionId int
, AYear int
, APer int
, Amount int
, constraint PK_Balance primary key (Id)
)
GO
insert #Version
select 0, 'History', 200701 union
select 153, 'Nov 2017', 201711 union
select 154, 'Dec 2017', 201712
insert #Balance
select 0, 2017, 10, 29327 union
select 0, 2017, 11, 351 union
select 0, 2017, 12, 6530 union
select 154, 2018, 1, 25000 union
select 154, 2018, 2, 39136 union
select 154, 2018, 3, 20000 union
select 153, 2017, 12, 3000 union
select 153, 2018, 1, 47000 union
select 153, 2018, 2, 35000
答案 0 :(得分:1)
这是一个简单的解决方案:
select v.id, b.Ayear, b.Aper, b.amount
from #Version v join #Balance b on v.historyTo >= (b.Ayear*100+b.Aper)
where v.Id != 0 and b.VersionId = 0
union
select B.VersionId, B.Ayear, B.Aper, B.amount from #Balance B
你可以在这里测试一下: http://rextester.com/CVEY79303
答案 1 :(得分:0)
我在查询中实现了逻辑,但可以进一步优化。
CREATE TABLE #Version (
Id INT
, [Name] VARCHAR(100)
, HistoryTo INT
, CONSTRAINT PK_Version PRIMARY KEY (Id)
)
GO
CREATE TABLE #Balance (
Id INT IDENTITY(1,1)
, VersionId INT
, AYear INT
, APer INT
, Amount INT
, CONSTRAINT PK_Balance PRIMARY KEY (Id)
)
GO
INSERT #Version
SELECT 0, 'History', 200701 UNION
SELECT 153, 'Nov 2017', 201711 UNION
SELECT 154, 'Dec 2017', 201712
INSERT #Balance
SELECT 0, 2017, 10, 29327 UNION
SELECT 0, 2017, 11, 351 UNION
SELECT 0, 2017, 12, 6530 UNION
SELECT 154, 2018, 1, 25000 UNION
SELECT 154, 2018, 2, 39136 UNION
SELECT 154, 2018, 3, 20000 UNION
SELECT 153, 2017, 12, 3000 UNION
SELECT 153, 2018, 1, 47000 UNION
SELECT 153, 2018, 2, 35000
SELECT * FROM #Version
SELECT * FROM #Balance
DROP TABLE IF EXISTS #TempBalance
CREATE TABLE #TempBalance (
Id INT IDENTITY(1,1)
, VersionId INT
, AYear INT
, APer INT
, Amount INT
, CONSTRAINT PK_TempBalance PRIMARY KEY (Id)
)
GO
DECLARE @CurrentId INT ;
DECLARE TMP_Cursor CURSOR DYNAMIC FOR
SELECT Id FROM #Version
OPEN TMP_Cursor
FETCH NEXT FROM TMP_Cursor INTO @CurrentId
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO #TempBalance
SELECT VersionId
, AYear
, APer
, Amount
FROM #Balance WHERE VersionId = @CurrentId
UNION ALL
SELECT DISTINCT
@CurrentId AS VersionId
, AYear
, APer
, Amount
FROM #TempBalance
WHERE CONCAT(AYear, APer) NOT IN (SELECT CONCAT(AYear, APer) FROM #Balance WHERE VersionId = @CurrentId)
FETCH NEXT FROM TMP_Cursor INTO @CurrentId
END
CLOSE TMP_Cursor
DEALLOCATE TMP_Cursor
SELECT
VersionId,
AYear,
APer,
Amount
FROM
(
SELECT
*
, ROW_NUMBER() OVER(PARTITION BY VersionId, AYear, APer ORDER BY Id DESC) AS Rank1
FROM #TempBalance
) AS T
WHERE
Rank1 = 1
ORDER BY
VersionId ASC
, AYear ASC
, APer ASC
答案 2 :(得分:0)
以下示例了解缺少的内容并添加已经存在的内容。
declare @Version table (Id int primary key, [Name] varchar(100), HistoryTo int);
declare @Balance table (Id int identity(1,1) primary key, VersionId int, AYear int, APer int, Amount int);
insert @Version (Id, [Name], HistoryTo) values
(0, 'History', 201701),(153, 'Nov 2017', 201711),(154, 'Dec 2017', 201712);
insert @Balance (VersionId, AYear, APer, Amount) values
(0, 2017, 10, 29327),(0, 2017, 11, 351),(0, 2017, 12, 6530),
(153, 2017, 12, 3000),(153, 2018, 1, 47000),(153, 2018, 2, 35000),
(154, 2018, 1, 25000),(154, 2018, 2, 39136),(154, 2018, 3, 20000);
select *
from (
select bv.VersionId, b0.AYear, b0.APer, b0.Amount
from (select * from @Balance where VersionId = 0) b0
cross join (select distinct VersionId from @Balance) bv
left join @Balance b1 on (b1.AYear = b0.AYear and b1.APer = b0.APer and b1.VersionId = bv.VersionId)
--join @Version v on (v.Id = bv.VersionId and v.historyTo <= (b0.Ayear*100+b0.Aper))
where b1.Id is null
union all
select b.VersionId, b.AYear, b.APer, b.Amount
from @Balance b
join @Version v on (v.Id = b.VersionId and v.historyTo <= (b.Ayear*100+b.Aper))
) q
order by VersionId, AYear, APer, Amount;
结果:
VersionId AYear APer Amount
--------- ----- ---- ------
0 2017 10 29327
0 2017 11 351
0 2017 12 6530
153 2017 10 29327
153 2017 11 351
153 2017 12 3000
153 2018 1 47000
153 2018 2 35000
154 2017 10 29327
154 2017 11 351
154 2017 12 6530
154 2018 1 25000
154 2018 2 39136
154 2018 3 20000