Sql 将计算值分布到多行

Sql 将计算值分布到多行,sql,sql-server,Sql,Sql Server,我有两张桌子 Table of projects ProjectID, SOP, IncomeA, IncomeB 1 2021-01 100.000 0 2 2022-11 5.000 2.000 列SOPOffset与列SOP的年份相关。因此,项目1在2021年和2022年有收入,而项目2在2022年、2023年和2024年有收入 现有查询的结果是 year income 2021 1.000 -- #1 offset

我有两张桌子

Table of projects

ProjectID, SOP,     IncomeA, IncomeB
1          2021-01  100.000      0
2          2022-11    5.000  2.000
SOPOffset
与列
SOP
的年份相关。因此,项目1在2021年和2022年有收入,而项目2在2022年、2023年和2024年有收入

现有查询的结果是

year  income
2021  1.000 -- #1 offset 0
2022  3.000 -- #1 offset 1 + #2 offset 0
2023    500 -- #2 offset 1
2024    500 -- #2 offset 2
一项新的要求是,
IncomeA
IncomeB
这两个列需要在每个项目中最多分配3年。这意味着项目1和项目2的SOPOffset将分别为2021年和2022年增加
50.000和
s,而项目2和项目3的SOPOffset将分别为2022年和2023年增加2333.34和2024年增加2333.33

year  income
2021  51.000    -- #1 offset 0 + (100.000 + 0)/2
2022  55.333,34 -- #1 offset 1 + #2 offset 0 + (100.000 + 0)/2 + 7000/3 (rounded up to 2333,34)
2023   2,833,34 -- #2 offset 1 + 7000/3 (rounded down to 2333,33)
2024   2,833,34 -- #2 offset 2 + 7000/3 (rounded down to 2333,33)
这个新的需求是否可以在单个查询中实现?我当前的解决方案是在应用程序代码本身中实现的,或者在SQL中使用循环等

编辑03.08.2020 15:30 根据注释中的要求,这是现有的查询,它使用稍微不同的表结构和一些附加信息来构建完整的结果集

SELECT 
    YEAR(cp.datSOP) + pv.intYearOffset,
    SUM(pv.decPrice / cr.decRate * pv.intVolume) as IntakeEUR
FROM
    tblProjectVolume pv
    INNER JOIN tblProject sp ON sp.intProjectId = pv.intProjectId
        INNER JOIN tblCustomerProject cp ON cp.intCustomerProjectId = sp.intCustomerProjectId AND (YEAR(cp.datSOP) + pv.intYearOffset >= 2019)
    INNER JOIN tblCurrency c ON c.intCurrencyId = sp.intCurrencyId
        INNER JOIN tblCurrencyRate cr ON cr.intCurrencyId = c.intCurrencyId AND cr.intYear = 2019
group by
    YEAR(cp.datSOP) + pv.intYearOffset
order by 
    YEAR(cp.datSOP) + pv.intYearOffset
详细结果有一个附加的联接和分组依据

SELECT 
    YEAR(cp.datSOP) + pv.intYearOffset, bu.intBusinessDivisionId,
    SUM(pv.decPrice / cr.decRate * pv.intVolume) as IntakeEUR
FROM
    tblProjectVolume pv
    INNER JOIN tblProject sp ON sp.intProjectId = pv.intProjectId
        INNER JOIN tblCustomerProject cp ON cp.intCustomerProjectId = sp.intCustomerProjectId AND (YEAR(cp.datSOP) + pv.intYearOffset >= 2019)
    INNER JOIN tblCurrency c ON c.intCurrencyId = sp.intCurrencyId
        INNER JOIN tblCurrencyRate cr ON cr.intCurrencyId = c.intCurrencyId AND cr.intYear = 2019
    INNER JOIN tblProductMapping pm ON pm.intProductMappingId = sp.intProductMappingId
        INNER JOIN tblBusinessUnit bu ON bu.intBusinessUnitId = pm.intBusinessUnitId
group by
    YEAR(cp.datSOP) + pv.intYearOffset, bu.intBusinessDivisionId
order by 
    YEAR(cp.datSOP) + pv.intYearOffset, bu.intBusinessDivisionId

关键的一点是你需要按年数分配收入。首先,你需要找出年数。这是在CTE
income
中完成的,它使用
count()
来确定每个项目的偏移量。一旦你有了它,就把总收入除以它

declare @projects table
(
    ProjectID   int,
    SOP     int,
    IncomeA     decimal(10,2),
    IncomeB     decimal(10,2)
)

declare @income table
(
    ProjectID   int,
    SOPOffset   int,
    Income      decimal(10,2)
)

insert into @projects
values  (1, 2021, 100000,    0),
        (2, 2022,   5000, 2000)

insert into @income
values  (1, 0, 1000),
    (1, 1, 2000),
    (2, 0, 1000),
    (2, 1,  500),
    (2, 2,  500)

; with income as
(
    select  ProjectID, SOPOffset, Income, 
            TotalOffset = count(*) over (partition by ProjectID)
    from    @income
)
select  year    = (p.SOP + i.SOPOffset),
       income   = SUM(  i.Income
                     +  ((p.IncomeA + p.IncomeB) / i.TotalOffset) )
from    @projects p
        inner join income i on  p.ProjectID = i.ProjectID
group by (p.SOP + i.SOPOffset)

附言:在你发布你的实际查询之前,我提出了这个查询。我相信您将能够根据您的查询进行调整

您可以显示您现有的查询吗?还请解释如何获得当前测试的结果query@Squirrel我已将其添加到该解决方案的初始POSTINGTANKS中,但这太容易了;)它忽略了两个要求:(a)将值分配到最多3年的时间;(b)在单个查询中。(a) 可通过
IIF
TotalOffset
计数处求解。但是(b)有点问题,我认为-而且不是,将带有收入的
嵌入select语句的
from
中不幸不是一个解决方案…我发布的解决方案只是一个查询。或者,在单个查询中,您所说的
到底是什么意思?
?由于需求发生了变化,我可以使用您的解决方案,只需稍作更改(重新保护)。以前,查询必须在SQL和应用程序使用的DB框架中实现,该应用程序只能执行功能有限的单个查询。
declare @projects table
(
    ProjectID   int,
    SOP     int,
    IncomeA     decimal(10,2),
    IncomeB     decimal(10,2)
)

declare @income table
(
    ProjectID   int,
    SOPOffset   int,
    Income      decimal(10,2)
)

insert into @projects
values  (1, 2021, 100000,    0),
        (2, 2022,   5000, 2000)

insert into @income
values  (1, 0, 1000),
    (1, 1, 2000),
    (2, 0, 1000),
    (2, 1,  500),
    (2, 2,  500)

; with income as
(
    select  ProjectID, SOPOffset, Income, 
            TotalOffset = count(*) over (partition by ProjectID)
    from    @income
)
select  year    = (p.SOP + i.SOPOffset),
       income   = SUM(  i.Income
                     +  ((p.IncomeA + p.IncomeB) / i.TotalOffset) )
from    @projects p
        inner join income i on  p.ProjectID = i.ProjectID
group by (p.SOP + i.SOPOffset)