Oracle SQL查询上一行结果
Posted
技术标签:
【中文标题】Oracle SQL查询上一行结果【英文标题】:Oracle SQL query previous row result 【发布时间】:2017-01-30 18:43:19 【问题描述】:我现在卡住了,现在正在获取解决此查询的逻辑。找到下表和输出。有表 A 和表 B 匹配两个列 ID 和 DATE。如果日期匹配,那么它应该将数量乘以百分比,否则它应该选择前一个百分比。
Table A Table B
ID Date Percent ID Date Qty
A 01/01/17 0.5 A 01/01/17 10
A 04/01/17 1 A 02/01/17 20
A 06/01/17 2 A 03/01/17 30
B 02/01/17 5 A 05/01/17 40
B 05/01/17 10 A 06/01/17 50
A 07/01/17 60
A 08/01/17 40
B 01/01/17 10
B 02/01/17 50
============================================
column column column comment comment comment
ID Date Qty Previous percent if row not matched
A 01/01/17 0.5 * 10 0.5 got new percent
A 02/01/17 0.5 * 20 0.5
A 03/01/17 0.5 * 30 0.5
A 04/01/17 1* 0 1 got new percent but no qty found
A 05/01/17 1 * 40 1
A 06/01/17 2 * 50 2 got new percent
B 01/01/17 10 * 0 0 no percent found
B 02/02/17 5 * 10 5 got new percent
B 5/1/17 10 * 0 10 got new percent
【问题讨论】:
“输出”表 (??) 显示日期为 17 年 4 月 1 日的一行,这两个输入表中都不存在。为什么?这是要求的一部分吗?如果是,请更新帖子以明确说明。 @mathguy: 04/01/17 在表 A 的第二行。??? @BobJarvis - 呃。我的意思是在表 B 中。更一般地说 - 是否要求所有月份都出现在最终结果中?但是后来我查看了其余的输出,它没有任何意义。例如,2017 年 5 月 5 日是怎么回事? (输出中的最后一行)我决定忽略“输出”并以“我的方式”解释问题。 @yAshu:在最后的“结果”行中,日期应该是“05/01/17”而不是“5/5/17”吗? 现在是 05/01/17。错别字 【参考方案1】:我将问题解释为“在表 B 中添加更多列” - 显示“最新”百分比,显示表 A 中的日期,以及表 B 中的“总数量”和“净数量” " 乘以适当的百分比。
如果表 A 中的每一行还需要一行,只需从最外层查询(靠近查询底部)删除 WHERE
子句。
with table_a ( id, dt, pct ) as (
select 'A', to_date('01/01/17', 'mm/dd/rr'), 0.5 from dual union all
select 'A', to_date('04/01/17', 'mm/dd/rr'), 1 from dual union all
select 'A', to_date('06/01/17', 'mm/dd/rr'), 2 from dual union all
select 'B', to_date('02/01/17', 'mm/dd/rr'), 5 from dual union all
select 'B', to_date('05/01/17', 'mm/dd/rr'), 10 from dual
), table_b ( id, dt, qty ) as (
select 'A', to_date('01/01/17', 'mm/dd/rr'), 10 from dual union all
select 'A', to_date('02/01/17', 'mm/dd/rr'), 20 from dual union all
select 'A', to_date('03/01/17', 'mm/dd/rr'), 30 from dual union all
select 'A', to_date('05/01/17', 'mm/dd/rr'), 40 from dual union all
select 'A', to_date('06/01/17', 'mm/dd/rr'), 50 from dual union all
select 'A', to_date('07/01/17', 'mm/dd/rr'), 60 from dual union all
select 'A', to_date('08/01/17', 'mm/dd/rr'), 40 from dual union all
select 'B', to_date('01/01/17', 'mm/dd/rr'), 10 from dual union all
select 'B', to_date('02/01/17', 'mm/dd/rr'), 50 from dual
)
-- end of test data (not part of the SQL query); query begins BELOW THIS LINE
select id, qty_date, pct_date, qty as gross_qty, pct, qty * pct as net_qty
from ( select id, dt as qty_date,
last_value(case flag when 0 then dt end ignore nulls)
over (partition by id order by dt) as pct_date,
last_value(pct ignore nulls)
over (partition by id order by dt, flag) as pct,
qty, flag
from ( select id, dt, pct, null as qty, 0 as flag
from table_a
union all
select id, dt, null as pct, qty, 1 as flag
from table_b
)
)
where flag = 1
order by id, qty_date -- if needed
;
输出:
ID QTY_DATE PCT_DATE GROSS_QTY PCT NET_QTY
-- ---------- ---------- ---------- ---------- ----------
A 2017-01-01 2017-01-01 10 .5 5
A 2017-02-01 2017-01-01 20 .5 10
A 2017-03-01 2017-01-01 30 .5 15
A 2017-05-01 2017-04-01 40 1 40
A 2017-06-01 2017-06-01 50 2 100
A 2017-07-01 2017-06-01 60 2 120
A 2017-08-01 2017-06-01 40 2 80
B 2017-01-01 10
B 2017-02-01 2017-02-01 50 5 250
9 rows selected.
【讨论】:
A 2017-05-01 2017-04-01 40 1 40 @yAshu - 为什么null
次(任何值)等于零,而不是null
?除此之外,我已经在我的回答中说过:“如果表 A 中的每一行还需要一行,只需从最外层查询(靠近查询底部)中删除 WHERE
子句。”你能找到吗?这是我答案的第二段!现在:如果您需要为net_qty
显示零而不是NULL
,请在外部查询的SELECT
中选择coalesce(qty, 0) * pct as net_qty
而不是简单的qty * pct
。我假设如果你没有pct
(B 的第一行)那么net_qty
应该仍然是null
,对吧?
我在使用分析函数 LAST VALUE 的查询中使用了相同的逻辑...。我来这里是想知道是否有其他替代解决方案可以解决此查询...但是您写的大致相同解决方案...好吧,谢谢@mathguy。赞!!
@yAshu - 还有其他方法可以解决这个问题,特别是使用连接。但是,在几乎所有情况下,如果您可以使用union all
和分析函数并避免连接,查询将运行得更快。我的理解是,正是出于这个原因引入了分析函数 - 以显着减少对耗时连接的需求。以上是关于Oracle SQL查询上一行结果的主要内容,如果未能解决你的问题,请参考以下文章
sql server和oracle中查询结果返回指定行数的语句
在 AngularJS 页面上显示多个 Oracle SQL 查询结果