如何将三个 select 查询合并为一个以在 Oracle 中实现如下所示的预期结果?

How to merge three select queries into one in order to achieve the desired result as below in Oracle?

目的是在每个项目的计划增量和实际增量第一次出现负值时推送 'N' 标志。 'Y' 标志应推入所有其余行。 Rank列定义顺序,Project ID定义一个项目的数据。

只能使用 select 个查询

使用下面的table结构 '''

CREATE TABLE payBackTable (projectID varchar2(10), quarterYear varchar2(10), Rank int, planned_delta int, actual_delta int ) 
INSERT INTO payBackTable values
( 'P001','Q1-2017', 1, 2000, 900)
( 'P001','Q2-2017', 2, 18000, 800)
( 'P001','Q3-2017', 3, 0, 7000)
( 'P001','Q4-2017', 4, 9000, -90)
( 'P001','Q1-2018', 5, -10, 9000)
( 'P001','Q2-2018', 6, 100, 70)
( 'P001','Q3-2018', 7, -90, -900)
( 'P001','Q4-2018', 8, 200, -8)
( 'P002', 'Q3-2016', 1, 1000, 90 )
( 'P002', 'Q4-2016', 2, -200, 90 )
( 'P002', 'Q1-2017', 3, 4000, -500 )
( 'P002', 'Q2-2017', 4, 10, -90 )
( 'P003', 'Q3-2021', 1, -10, 700 )
( 'P003', 'Q4-2021', 2, 100, -800 )
( 'P003', 'Q1-2022', 3, -100, -900 )
( 'P003', 'Q2-2022', 3, -90, 100 )

'''

来源Table

项目编号 季度 排名 计划增量 实际增量
P001 2017 年第一季度 1 2000 900
P001 2017 年第 2 季度 2 18000 800
P001 2017 年第 3 季度 3 0 7000
P001 2017 年第四季度 4 9000 -90
P001 2018 年第一季度 5 -10 9000
P001 2018 年第二季度 6 100 70
P001 2018 年第 3 季度 7 -90 -900
P001 2018 年第四季度 8 200 -8
P002 2016 年第 3 季度 1 1000 90
P002 2016 年第四季度 2 -200 90
P002 2017 年第一季度 3 4000 -500
P002 2017 年第 2 季度 4 10 -90
P003 2021 年第 3 季度 1 -10 700
P003 2021 年第 4 季度 2 100 -800
P003 2022 年第一季度 3 -100 -900
P003 2022 年第二季度 4 -90 100

想要的结果

项目编号 季度 排名 计划增量 实际增量 计划中的标志 实际标志
P001 2017 年第一季度 1 2000 900 Y Y
P001 2017 年第 2 季度 2 18000 800 Y Y
P001 2017 年第 3 季度 3 0 7000 Y Y
P001 2017 年第四季度 4 9000 -90 Y N
P001 2018 年第一季度 5 -10 9000 N Y
P001 2018 年第二季度 6 100 70 Y Y
P001 2018 年第 3 季度 7 -90 -900 Y Y
P001 2018 年第四季度 8 200 -8 Y Y
P002 2016 年第 3 季度 1 1000 90 Y Y
P002 2016 年第四季度 2 -200 90 N Y
P002 2017 年第一季度 3 4000 -500 Y N
P002 2017 年第 2 季度 4 10 -90 Y Y
P003 2021 年第 3 季度 1 -10 700 N Y
P003 2021 年第 4 季度 2 100 -800 Y N
P003 2022 年第一季度 3 -100 -900 Y Y
P003 2022 年第二季度 4 -90 100 Y Y

我已经能够 table 使用三个不同的 queries/batch 作业来推送所需的结果,但不确定如何在单个 query/batch 作业中实现它。 在 Planned Flag

中推送 'N' flag
select projectID,quarterYear, 'N' from(
select  projectID, quarterYear,
Row_number() OVER(PARTITION BY projectID ORDER BY to_number(Rank)) 
as rownumm from payBackTable 
where  to_number(planned_delta) < 0) where  rownumm = 1

将 'N' 标志推入 Actual Flag

select projectID,quarterYear, 'N' from(
select  projectID, quarterYear,
Row_number() OVER(PARTITION BY projectID ORDER BY to_number(Rank)) 
as rownumm from payBackTable 
where  to_number(actual_delta) < 0) where  rownumm = 1

在Planned Flag和Actual Flag中推送'Y' flag

select projectID,
quarterYear,
case planned_Flag when NULL then 'Y' ELSE planned_Flag END, 
case actual_Flag when NULL then 'Y' ELSE actual_Flag END
from payBackTable

您可以根据每个值的符号获得项目中每个值的排名

select projectid, quarteryear, rank, planned_delta, actual_delta,
  dense_rank() over (partition by projectid, sign(planned_delta) order by rank) as flag1,
  dense_rank() over (partition by projectid, sign(actual_delta) order by rank) as flag2
from paybacktable
order by projectid, rank
PROJECTID QUARTERYEAR RANK PLANNED_DELTA ACTUAL_DELTA FLAG1 FLAG2
P001 Q1-2017 1 2000 900 1 1
P001 Q2-2017 2 18000 800 2 2
P001 Q3-2017 3 0 7000 1 3
P001 Q4-2017 4 9000 -90 3 1
P001 Q1-2018 5 -10 9000 1 4
P001 Q2-2018 6 100 70 4 5
P001 Q3-2018 7 -90 -900 2 2
P001 Q4-2018 8 200 -8 5 3

...

然后将它们用作 case 表达式的一部分;如果排名 i1 的值为负数,那么它是第一个负值:

select projectid, quarteryear, rank, planned_delta, actual_delta,
  case
    when sign(planned_delta) = -1
      and dense_rank() over (partition by projectid, sign(planned_delta) order by rank) = 1
    then 'N'
    else 'Y'
  end as planned_flag,
  case
    when sign(actual_delta) = -1
      and dense_rank() over (partition by projectid, sign(actual_delta) order by rank) = 1
    then 'N'
    else 'Y'
  end as actual_flag
from paybacktable
order by projectid, rank
PROJECTID QUARTERYEAR RANK PLANNED_DELTA ACTUAL_DELTA PLANNED_FLAG ACTUAL_FLAG
P001 Q1-2017 1 2000 900 Y Y
P001 Q2-2017 2 18000 800 Y Y
P001 Q3-2017 3 0 7000 Y Y
P001 Q4-2017 4 9000 -90 Y N
P001 Q1-2018 5 -10 9000 N Y
P001 Q2-2018 6 100 70 Y Y
P001 Q3-2018 7 -90 -900 Y Y
P001 Q4-2018 8 200 -8 Y Y
P002 Q3-2016 1 1000 90 Y Y
P002 Q4-2016 2 -200 90 N Y
P002 Q1-2017 3 4000 -500 Y N
P002 Q2-2017 4 10 -90 Y Y
P003 Q3-2021 1 -10 700 N Y
P003 Q4-2021 2 100 -800 Y N
P003 Q2-2022 3 -90 100 Y Y
P003 Q1-2022 3 -100 -900 Y Y

db<>fiddle

select P1.projectID, P1.quarterYear, P1.Rank, P1.planned_Delta, P1.actual_Delta,
    case when Rank = X1.RankMin then 'N' ELSE 'Y' END plannedFlag , 
    case when Rank = X2.RankMin then 'N' ELSE 'Y' END actualFlag 
from payBackTable P1 
left join (
    select projectID, min(Rank) RankMin
    from payBackTable P2 
    where Planned_Delta < 0
    group by projectID
    ) X1 on P1.projectID = X1.projectID

left join (
    select projectID, min(Rank) RankMin
    from payBackTable P2 
    where Actual_Delta < 0
    group by projectID
    ) X2 on P1.projectID = X2.projectID