在XPATH中包含()标记名称和属性值

时间:2017-04-19 11:43:04

标签: oracle select xpath

我有一个XML列,它与下面提到的类似。

<appl>
<sftp_job name = "test1_ftp">
<ftp_job name = "test2_ftp">
<link name="testlink1">
<tag name ="task1_ftp">
<unix_job name="test123_ftp">
</appl>

我的要求是获取以“_ftp”结尾的所有atrributes的值,如下所述。

test1_ftp
test2_ftp
task1_ftp
test123_ftp

我有以下SQL语句,它工作正常。

SELECT JOB_NAME
  FROM
    (SELECT q.jobname AS JOB_NAME
     FROM DFTAB1
     LEFT JOIN xmltable('/appl/*[contains(name(),"_job") or 
                                 contains(name(),"link") or 
                                 contains(name(),"task") ]' 
   PASSING XMLTYPE(DEF) columns jobname VARCHAR2(20) path '@name')q ON (1=1)
     )
 WHERE JOB_NAME LIKE '%_ftp%'

这是有效的。

我是否可以在单个SELECT语句中执行此操作。

2 个答案:

答案 0 :(得分:2)

您可以在XPath查询中组合布尔运算符:

SELECT x.job_name
FROM DFTAB1 d
CROSS JOIN XMLTable(
  '/appl/*[(contains(name(),"_job")
    or contains(name(),"link")
    or contains(name(),"task"))
    and (ends-with(@name, "_ftp"))]' 
  PASSING XMLTYPE(d.DEF)
  COLUMNS job_name VARCHAR2(20) path '@name'
) x;

我使用了交叉连接而不是左外连接,这实际上是一个内部连接,并且由于虚拟条件而实际上是交叉连接。我刚刚将生成的列调用为您希望它最终的结果,因此您不需要别名。

使用示例XML进行演示(带标签关闭)

with DFTAB1 (DEF) as (
  select '<appl>
<sftp_job name = "test1_ftp" />
<ftp_job name = "test2_ftp" />
<link name="testlink1" />
<tag name ="task1_ftp" />
<unix_job name="test123_ftp" />
</appl>' from dual
)
SELECT x.job_name
FROM DFTAB1 d
CROSS JOIN XMLTable(
  '/appl/*[(contains(name(),"_job")
    or contains(name(),"link")
    or contains(name(),"task"))
    and (ends-with(@name, "_ftp"))]' 
  PASSING XMLTYPE(d.DEF)
  COLUMNS job_name VARCHAR2(20) path '@name'
) x;

JOB_NAME            
--------------------
test1_ftp
test2_ftp
test123_ftp

与原始查询获得的结果相同;由于task1_ftp与原始tag支票不符,因此未包含contains

虽然存在细微的差别,但我认为从问题的措辞来看,这实际上是正确的,而且你的原文并不完整。当你执行LIKE '%_ftp%'时,下划线也是一个单字符的通配符,因此匹配说abcftp,这是我认为你不想要的。等效值将被转义为LIKE '%\_ftp%' ESCAPE '\'

正如MTO所提到的,一个更重要的变化是,您的查询在作业名称的任何位置查找_ftp(或者,如上所述,实际上只是ftp)。您的问题实际上是以“_ftp”结尾,因此您的描述和查询不匹配。如果您确实希望它在属性值中的任何位置,请再次使用contains而不是ends-with

SELECT x.job_name
FROM DFTAB1 d
CROSS JOIN XMLTable(
  '/appl/*[(contains(name(),"_job")
    or contains(name(),"link")
    or contains(name(),"task"))
    and (contains(@name, "_ftp"))]' 
  PASSING XMLTYPE(d.DEF)
  COLUMNS job_name VARCHAR2(20) path '@name'
) x;

虽然结果与您的样本相同。

答案 1 :(得分:1)

SELECT q.jobname AS JOB_NAME
FROM   DFTAB1 d
       CROSS JOIN
       XMLTABLE(
         '/appl/*[contains(name(),"_job") or 
                  contains(name(),"link") or 
                  contains(name(),"task") ]' 
         PASSING XMLTYPE(d.DEF)
         columns jobname VARCHAR2(20) path '@name'
       ) q
WHERE  q.JOBNAME LIKE '%_ftp%'