PL SQL多行分析

时间:2017-11-21 09:07:30

标签: sql oracle

我在Oracle,INVOICES和HOLDS中有两个表,我使用invoice_id连接。并非所有发票都有效​​,但有些发票会有多个保留事件。我想只选择一个发票并解码release_status字段。 如果有多个保持事件,我需要分析它是否已被释放。如果一行没有释放代码,则仍然保留整个发票。 示例表:

Invoice_num     |Hold_Reason    |Release_Lookup_code  

10001           |Inv Hold       |Quick release  
10002           |Inv Hold       |Quick release  
10003           |Inv Hold       |(NULL)  
10004           |Inv Hold       |Quick release  
10004           |Inv Hold       |Quick release  
10004           |Amt Hold       |(NULL)  
10005           |Inv Hold       |Variance Corrected  
10005           |Inv Hold       |Quick release  
10006           |  (NULL)       |(NULL)  

我想要显示的结果:

Invoice num |Hold Reason    |Hold Status 

10001       |Inv Hold       |Released  
10002       |Inv Hold       |Released  
10003       |Inv Hold       |Held  
10004       |Inv Hold       |Held  
10005       |Inv Hold       |Released  
10006       |(NULL)         |Not Held 

目前我只有这个代码,它会带回多行:

select
inv.invoice_num,
hold.hold_reason,
(CASE WHEN hold.invoice_id is not null                                              
then (CASE WHEN HOLD.RELEASE_LOOKUP_CODE is null then 'HELD' else 'RELEASED' END)   
else 'NOT HELD' END) Hold_Status
from AP.AP_INVOICES_ALL INV,
AP.AP_HOLDS_ALL HOLD
WHERE inv.invoice_id = hold.invoice_id (+)
order by 1

我想过计算发票的数量,但之后我仍然需要分析Release_Lookup_Code字段的内容。 我不是在寻找完整的答案,只是关于我应该如何进行的一些建议。

2 个答案:

答案 0 :(得分:2)

像这样的东西。在发票保留表上进行复制。

   with AP_HOLDS_ALL(invoice_id, Hold_Reason, Release_Lookup_code) as
           (select 10001, 'Inv Hold', 'Quick release' from dual
            union all
            select 10002, 'Inv Hold', 'Quick release' from dual
            union all
            select 10003, 'Inv Hold', '' from dual
            union all
            select 10004, 'Inv Hold', 'Quick release' from dual
            union all
            select 10004, 'Inv Hold', 'Quick release' from dual
            union all
            select 10004, 'Amt Hold', '' from dual
            union all
            select 10005, 'Inv Hold', 'Variance Corrected' from dual
            union all
            select 10005, 'Inv Hold', 'Quick release' from dual
            union all
            select 10006, '', '' from dual)
       , AP_HOLDS_ALL_deplicated as
           (select s.*
                 , row_number()
                   over(partition by invoice_id
                        order by decode(Release_Lookup_code,  'Quick release', 1,  'Variance Corrected', 2,  3) desc)
                     rn
              from AP_HOLDS_ALL s)
       , AP_INVOICES_ALL(invoice_id) as
           (select 10001 from dual
            union all
            select 10002 from dual
            union all
            select 10003 from dual
            union all
            select 10004 from dual
            union all
            select 10005 from dual
            union all
            select 10006 from dual)
      select --inv.invoice_num,
             inv.invoice_id
           , hold.hold_reason
           , (case
                when hold.invoice_id is not null then
                  (case
                     when HOLD.RELEASE_LOOKUP_CODE is null then 'HELD'
                     else 'RELEASED'
                   end)
                else
                  'NOT HELD'
              end)
               Hold_Status
        from AP.AP_INVOICES_ALL INV, AP.AP_HOLDS_ALL_deplicated HOLD
       where inv.invoice_id = hold.invoice_id(+) and HOLD.rn = 1
    order by 1

答案 1 :(得分:2)

与@ Arkadiusz的答案类似的想法,但使用keep ... dense_rank而不是明确的步骤来查找行号:

-- CTEs to provide your sample data
with ap_invoices_all (invoice_id) as (
  select 10001 from dual
  union all select 10002 from dual
  union all select 10003 from dual
  union all select 10004 from dual
  union all select 10005 from dual
  union all select 10006 from dual
), 
ap_holds_all (invoice_id, hold_reason, release_lookup_code) as (
  select 10001, 'Inv Hold', , 'Quick release' from dual
  union all select 10002, 'Inv Hold', 'Quick release' from dual
  union all select 10003, 'Inv Hold', null from dual
  union all select 10004, 'Inv Hold', 'Quick release' from dual
  union all select 10004, 'Inv Hold', 'Quick release' from dual
  union all select 10004, 'Amt Hold', null from dual
  union all select 10005, 'Inv Hold', 'Variance Corrected' from dual
  union all select 10005, 'Inv Hold', 'Quick release' from dual
  union all select 10006, null, null from dual
)
-- end of CTEs for sample data
select
  inv.invoice_id,
  max(hold.hold_reason) keep (dense_rank last order by case
      when hold.release_lookup_code is null then 1 else 0
    end) as hold_reason,
  case
    when max(hold.hold_reason) is null then 'NOT HELD'
    when max(hold.release_lookup_code)
      keep (dense_rank last order by case
          when hold.release_lookup_code is null then 1 else 0
        end) is not null then 'RELEASED'
    else 'HELD'
  end as hold_status
from ap_invoices_all inv
left join ap_holds_all hold
on hold.invoice_id = inv.invoice_id
group by inv.invoice_id
order by 1;

得到:

INVOICE_ID HOLD_REA HOLD_STA
---------- -------- --------
     10001 Inv Hold RELEASED
     10002 Inv Hold RELEASED
     10003 Inv Hold HELD    
     10004 Amt Hold HELD    
     10005 Inv Hold RELEASED
     10006          NOT HELD

排名是优先保留具有空释放代码的保留记录,既可以找到适当的保留原因,也可以决定是否存在任何未结保留 - 确定是否保留或释放。

对于这个版本,如果您有一个发票的两个未结保留,那么您只会看到它报告一次,即使保留原因不同(例如,如果您同时保持amt和inv保持打开10004)。如果你想看到两者,那么你可以按两个字段进行分组,这将略微简化查询的其余部分;但是你也会因为这两个原因而看到释放。如果存在偏好,您还可以优先考虑在该场景中看到哪种持有原因。