如何将三个选择查询合并为一个,以在 Oracle 中实现如下所需的结果?

Posted

技术标签:

【中文标题】如何将三个选择查询合并为一个,以在 Oracle 中实现如下所需的结果?【英文标题】:How to merge three select queries into one in order to achieve the desired result as below in Oracle? 【发布时间】:2021-09-20 15:07:33 【问题描述】:

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

只能使用选择查询

使用下表结构 '''

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 )

'''

源表

Project ID Quarter-Year Rank Planned Delta Actual Delta
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 4 -90 100

想要的结果

Project ID 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 Q1-2022 3 -100 -900 Y Y
P003 Q2-2022 4 -90 100 Y Y

我已经能够使用三个不同的查询/批处理作业来实现表以推送所需的结果,但不确定如何在单个查询/批处理作业中实现这一点。 在计划标志中推送“N”标志

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'标志

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

在计划标志和实际标志中推送“Y”标志

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

【问题讨论】:

Edit问题并完成minimal reproducible example,即涉及的表或其他对象的CREATE语句(粘贴文本,不要使用图像, 不要链接到外部站点), INSERT 用于示例数据 (dito) 的语句以获得所需的结果。 我已经更正了,请指教 你还需要 CREATE TABLE / INSERT 如下:CREATE TABLE X(ProjectID varchar2, QuarterYear varchar2, Rank int, PlannedDelta int, ActualDelta int )INSERT INTO X( ProjectID, QuarterYear, Rank, PlannedDelta, ActualDelta )select 'P001', 'Q1-2017', 1, 2000, 900 from dual union allselect 'P001', 'Q1-2017', 2, 18000, 800 from dual union all...select 'P003', 'Q1-2022', 4, -90, 100 from dual 嗨@GauravKanodia 对不起,我把它红了三遍,仍然无法得到它。据我所知,只有当值为负时才需要设置“N”,对吧? 您的createinsert 都无效 - 您需要提供 varchar2 列的大小,而 Oracle 不支持多行插入的语法。您是否将 Oracle 与 mysql 混淆了? 【参考方案1】:

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

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

【讨论】:

【参考方案2】:
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

【讨论】:

以上是关于如何将三个选择查询合并为一个,以在 Oracle 中实现如下所需的结果?的主要内容,如果未能解决你的问题,请参考以下文章

将日期附加到字符串以在 oracle 中获取表名并对其进行选择查询

将多个单独的查询合并为一个以在Elasticsearch中获取聚合结果

只是想知道如何使用合并语句将下面的查询转换为 oracle 查询?

将三个使用 1:* 关系的查询合并为一个查询

Postgres如何将2个单独的选择查询合并为1个

需要哪些组件以及如何传输此查询以在 ODI 中使用?