如何将三个选择查询合并为一个,以在 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 all
select 'P001', 'Q1-2017', 2, 18000, 800 from dual union all
...select 'P003', 'Q1-2022', 4, -90, 100 from dual
嗨@GauravKanodia 对不起,我把它红了三遍,仍然无法得到它。据我所知,只有当值为负时才需要设置“N”,对吧?
您的create
和insert
都无效 - 您需要提供 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中获取聚合结果