Oracle SQL:没有listagg结果时返回null值

时间:2016-06-20 08:04:51

标签: sql oracle oracle10g listagg

我使用以下脚本返回一些基本信息。该脚本返回65行(如预期的那样)......

select unique
       trunc(li.cre_dat) cre_date,
       li.cre_usr,
       li.catnr,
       li.av_part_no,
       li.artist,
       li.title,
       li.prodtyp,
       li.packtyp,
       nvl(sp.name_for_customer,sp.name) pack_type 
from   leos_item li,
       scm_packtyp sp
where  li.cunr in ('816900','816901','816902')
and    li.item_type = 'FP'
and    li.av_part_no is null
and    trunc(li.cre_dat) >= '01-JAN-2016'
and    li.model_force_creation_idc != 'Y'
and    li.i_status != 'I'
and    li.packtyp = sp.packtyp

...但是,当我将Listagg添加到我的选择中时,报告只返回55行。 10行没有listagg结果因此从结果中省略...

select unique
       trunc(li.cre_dat) cre_date,
       li.cre_usr,
       li.catnr,
       li.av_part_no,
       li.artist,
       li.title,
       li.prodtyp,
       li.packtyp,
       nvl(sp.name_for_customer,sp.name) pack_type,
       regexp_replace(listagg(nvl(bom.av_part_no,'No'), ', ')
         within group (order by bom.item_id),'([^,]+)(,\1)+', '\1') masters
from   leos_item li,
       scm_packtyp sp,
       TABLE(leos_flatbom_pkg.GetFlatBOM(li.item_id)) bom,
       leos_item li1 
where  li.cunr in ('816900','816901','816902')
and    li.item_type = 'FP'
and    li.av_part_no is null
and    trunc(li.cre_dat) >= '01-JAN-2016'
and    li.model_force_creation_idc != 'Y'
and    li.i_status != 'I'
and    li.packtyp = sp.packtyp
and    bom.item_id = li1.item_id
and    li1.item_type = 'MT'
group by li.cre_dat,
         li.cre_usr,
         li.catnr,
         li.av_part_no,
         li.artist,
         li.title,
         li.prodtyp,
         li.packtyp,
         nvl(sp.name_for_customer,sp.name)

但是,我还需要看到这些线条。有没有办法返回没有找到listagg结果的10行。我尝试了以下nullif和nvl的组合,但没有运气;

nullif(regexp_replace(listagg(nvl(bom.av_part_no,'No'), ', ') within group (order by bom.item_id),'([^,]+)(,\1)+', '\1'),'No Master')

nvl(regexp_replace(listagg(nvl(bom.av_part_no,'No'), ', ') within group (order by bom.item_id),'([^,]+)(,\1)+', '\1'),'No Master')

1 个答案:

答案 0 :(得分:1)

问题不在LISTAGG,而是您正在对TABLE的{​​{1}}集合表达式执行内连接,并且包含零行,因此父行被过滤掉了结果。

将其替换为相关的子查询,如下所示:

leos_flatbom_pkg.GetFlatBOM(li.item_id)

其他一些观点:

  • 请更改为使用ANSI连接语法。旧的Oracle逗号连接语法很难知道如何连接列(特别是对于外连接),因为连接条件隐藏在select unique trunc(li.cre_dat) cre_date, li.cre_usr, li.catnr, li.av_part_no, li.artist, li.title, li.prodtyp, li.packtyp, nvl(sp.name_for_customer,sp.name) pack_type, ( SELECT regexp_replace(listagg(nvl(bom.av_part_no,'No'), ', ') within group (order by bom.item_id),'([^,]+)(,\1)+', '\1') FROM TABLE( leos_flatbom_pkg.GetFlatBOM(li.item_id)) bom INNER JOIN leos_item li1 ON ( bom.item_id = li1.item_id ) WHERE li1.item_type = 'MT' ) masters from leos_item li INNER JOIN scm_packtyp sp ON ( li.packtyp = sp.packtyp ) where li.cunr in ('816900','816901','816902') and li.item_type = 'FP' and li.av_part_no is null and li.cre_dat >= DATE '2016-01-01' and li.model_force_creation_idc != 'Y' and li.i_status != 'I' 子句中。
  • 不要将字符串文字用于日期(即'01 -JAN-2016')Oracle会使用WHERE会话参数作为格式掩码对它们执行隐式TO_DATE(),如果这种情况发生变化然后查询将中断(无需更改查询的文本),这将是一个痛苦的调试。更糟糕的是,这是一个会话参数,因此一个用户可以更改它,然后它将适用于其他所有人而不是他们。使用日期文字(即NLS_DATE_FORMAT)或明确调用DATE '2016-01-01'并提供格式屏蔽并更正TO_DATE()设置。
  • NLS因此如果li.cre_dat >= TRUNC( li.cre_dat )为真,则TRUNC( li.cre_dat ) >= DATE '2016-01-01'也将为真。结论是你可以消除li.cre_dat >= DATE '2016-01-01'电话。

您也可以使用第二个查询解决此问题,并将TRUNC()收集表达式转换为TABLE

OUTER JOIN