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中查询结果返回指定行数的语句

在 Oracle 中连接 SQL 查询的结果

在 AngularJS 页面上显示多个 Oracle SQL 查询结果

oracle 一行转多行

Oracle在查询Sql中不使用order by,导致数据量足够大的时候同样的sql查询的结果顺序不同?

如何将Oracle查询结果多行数据转成一行平铺显示?