繁体   English   中英

如何在Oracle中使用XMLTABLE内部联接三个表

[英]How to inner join three tables with XMLTABLE in Oracle

我有一个名为XML_INFRASTRUCTURE的表,该表具有以下设计:

COLUMN_NAME  | DATA_TYPE          | NULLABLE
-------------|--------------------|--------
XMLI_ID      | NUMBER(10,0)       | No
FILENAME     | VARCHAR2(255 CHAR) | Yes
LAST_VERSION | DATE               | Yes
XML_RAW      | CLOB               | Yes

在此表中,我将通过FTP接收的所有XML文件存储为XMLTYPE。 我使用XMLTABLE来获取信息,并且在开始加入表之前,一切都很好。

XML_INFRASTRUCTURE我具有以下数据:

XMLI_ID | FILENAME     | LAST_VERSION | XML_RAW
--------|--------------|--------------|--------------------------------
1       | ptcar        | 07-JAN-18    | <?xml version="1.0" encoding="ISO-8859-1"?><cern:ptcars creationDate="2018-03-16T19:35:54" xmlns:cern="http://www.website.com/Infrastructure" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.website.com/Infrastructure ../ns/infrastructure.xsd"><cern:ptcar id="1" validFromDate="1996-06-02" validToDate="2007-12-08" ....>
2       | ptrefColumn  | 07-JAN-18    | <?xml version="1.0" encoding="ISO-8859-1"?><cern:ptrefColumns creationDate="2018-03-20T11:33:21" xmlns:cern="http://www.website.com/Infrastructure" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.website.com/Infrastructure ../ns/infrastructure.xsd"><cern:ptrefColumn id="279" validFromDate="1998-04-01" validToDate="2001-06-11" ....> 
3       | ptref        | 07-JAN-18    | <?xml version="1.0" encoding="ISO-8859-1"?><cern:ptrefs creationDate="2018-03-20T11:33:05" xmlns:cern="http://www.website.com/Infrastructure"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.website.com//Infrastructure ../ns/infrastructure.xsd"><cern:ptref id="232" validFromDate="1998-04-01" validToDate="2001-06-11" ....>

接下来,我有以下要求:

给定值:ptrefId和givenDate

select a.longNameFrench , a.longNameDutch
from   ptcar as a, 
       ptrefColumn as b,
       ptref as c
where c.id = ptrefId
and b.id = c.ptrefColumnId
and a.id = b.ptcarId
and a.validFromDate <= givenDate
and a.validToDate >= givenDate
and b.validFromDate <= givenDate
and b.validToDate >= givenDate
and c.validFromDate <= givenDate
and c.validToDate >= givenDate

因此,知道了这一点,我尝试使用XMLTABLE删除XML,但是我不知道如何启动和运行联接。 如您所见,我尝试链接XMLTABLE,但是像这样,它已经运行了一个多小时。

SELECT X.LongNameFrench, X.LongNameDutch
FROM XML_Infrastructure,
    XMLTABLE(
        '$d/*:ptcars/*:ptcar'
        PASSING XMLTYPE(XML_Infrastructure.XML_RAW) as "d"
        COLUMNS
            Id              VARCHAR2(10)    PATH    '@*:id',
            LongNameFrench  VARCHAR2(60)    PATH    '@*:longNameFrench',
            LongNameDutch   VARCHAR2(60)    PATH    '@*:longNameDutch',
            ValidFromDate   VARCHAR2(10)    PATH    '@*:validFromDate',
            ValidToDate     VARCHAR2(10)    PATH    '@*:validToDate'
    ) AS X,
    XMLTABLE(
        '$d/*:ptrefColumns/*:ptrefColumn'
        PASSING XMLTYPE(XML_Infrastructure.XML_RAW) as "d"
        COLUMNS
            Id              VARCHAR2(10)    PATH    '@*:id',
            ValidFromDate   VARCHAR2(10)    PATH    '@*:validFromDate',
            ValidToDate     VARCHAR2(10)    PATH    '@*:validToDate'
    ) AS Y,
    XMLTABLE(
        '$d/*:ptrefs/*:ptref'
        PASSING XMLTYPE(XML_Infrastructure.XML_RAW) as "d"
        COLUMNS
            Id              VARCHAR2(10)    PATH    '@*:id',
            ValidFromDate   VARCHAR2(10)    PATH    '@*:validFromDate',
            ValidToDate     VARCHAR2(10)    PATH    '@*:validToDate'
    ) AS Z
WHERE Z.Id = '512'
AND FILENAME = 'ptcar';

建议非常欢迎! (对不起,信息过多)

您将在同一XML文档中创建三个XMLTable结果X,Y和Z,并且仅具有ptcar节点-因此Y和Z找不到任何数据(因为没有匹配这些XPath的节点)。

鉴于这三个XML文档之间的相似之处,并且假设您所显示的ID节点都应具有相同的值(示例数据中的情况并非如此),则可以使用单个XMLTable提取所有所有文档的相关数据:

SELECT X.Name, X.Id, X.ValidFromDate, X.ValidToDate, X.LongNameFrench, X.LongNameDutch
FROM XML_Infrastructure
CROSS JOIN XMLTABLE(
        '$d/*/*'
        PASSING XMLTYPE(XML_Infrastructure.XML_RAW) as "d"
        COLUMNS
            Name            VARCHAR2(10)    PATH    './local-name()',
            Id              NUMBER          PATH    '@*:id',
            LongNameFrench  VARCHAR2(60)    PATH    '@*:longNameFrench',
            LongNameDutch   VARCHAR2(60)    PATH    '@*:longNameDutch',
            ValidFromDate   DATE            PATH    '@*:validFromDate',
            ValidToDate     DATE            PATH    '@*:validToDate'
    ) X;

这使用通配符来获取任何子节点,但是您可以过滤掉,如果您有其他类型,则未显示。 它还添加了一个name列,以便您可以知道每一行来自哪个文档(或者,如果愿意,可以包括文件名)。 它将为所有三个属性都不存在的属性提供空值。

然后在CTE中使用它,并将其自身连接两次:

WITH cte AS (
  SELECT X.Name, X.Id, X.ValidFromDate, X.ValidToDate, X.LongNameFrench, X.LongNameDutch
  FROM XML_Infrastructure
  CROSS JOIN XMLTABLE(
          '$d/*/*'
          PASSING XMLTYPE(XML_Infrastructure.XML_RAW) as "d"
          COLUMNS
              Name            VARCHAR2(30)    PATH    './local-name()',
              Id              NUMBER          PATH    '@*:id',
              LongNameFrench  VARCHAR2(60)    PATH    '@*:longNameFrench',
              LongNameDutch   VARCHAR2(60)    PATH    '@*:longNameDutch',
              ValidFromDate   DATE            PATH    '@*:validFromDate',
              ValidToDate     DATE            PATH    '@*:validToDate'
      ) AS X
)
select a.longNameFrench, a.longNameDutch
from cte a
join cte b on b.id = a.id
join cte c on c.id = b.id
where c.name = 'ptref'
and b.name = 'ptrefColumn'
and a.name = 'ptcar'
and c.id = ptrefId
and a.validFromDate <= givenDate
and a.validToDate >= givenDate
and b.validFromDate <= givenDate
and b.validToDate >= givenDate
and c.validFromDate <= givenDate
and c.validToDate >= givenDate;

这有点类似于为每种文档类型创建查询视图,然后将其合并,但是不需要任何新的永久对象。

将您的部分样本数据放在另一个CTE中,并将所有ID设置为512,并在ptcar添加缺少的名称:

with XML_INFRASTRUCTURE (XMLI_ID, FILENAME, LAST_VERSION, XML_RAW) as (
  select cast (1 as number(2,0)), cast('ptcar' as varchar2(255)), date '2018-01-07', to_clob('<?xml version="1.0" encoding="ISO-8859-1"?>
<cern:ptcars creationDate="2018-03-16T19:35:54" xmlns:cern="http://www.website.com/Infrastructure" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.website.com/Infrastructure ../ns/infrastructure.xsd">
 <cern:ptcar id="512" validFromDate="1996-06-02" validToDate="2007-12-08" longNameFrench="Jean Dupont" longNameDutch="Jan Jansen"/>
</cern:ptcars>') from dual
  union all select 2, 'ptrefColumn', date '2018-01-07', to_clob('<?xml version="1.0" encoding="ISO-8859-1"?>
<cern:ptrefColumns creationDate="2018-03-20T11:33:21" xmlns:cern="http://www.website.com/Infrastructure" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.website.com/Infrastructure ../ns/infrastructure.xsd">
 <cern:ptrefColumn id="512" validFromDate="1998-04-01" validToDate="2001-06-11" />
</cern:ptrefColumns>') from dual
  union all select 3, 'ptref', date '2018-01-07', to_clob('<?xml version="1.0" encoding="ISO-8859-1"?>
<cern:ptrefs creationDate="2018-03-20T11:33:05" xmlns:cern="http://www.website.com/Infrastructure" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.website.com//Infrastructure ../ns/infrastructure.xsd">
 <cern:ptref id="512" validFromDate="1998-04-01" validToDate="2001-06-11" />
</cern:ptrefs>') from dual
),
cte AS (
  SELECT X.Name, X.Id, X.ValidFromDate, X.ValidToDate, X.LongNameFrench, X.LongNameDutch
  FROM XML_Infrastructure
  CROSS JOIN XMLTABLE(
          '$d/*/*'
          PASSING XMLTYPE(XML_Infrastructure.XML_RAW) as "d"
          COLUMNS
              Name            VARCHAR2(30)    PATH    './local-name()',
              Id              NUMBER          PATH    '@*:id',
              LongNameFrench  VARCHAR2(60)    PATH    '@*:longNameFrench',
              LongNameDutch   VARCHAR2(60)    PATH    '@*:longNameDutch',
              ValidFromDate   DATE            PATH    '@*:validFromDate',
              ValidToDate     DATE            PATH    '@*:validToDate'
      ) AS X
)
select a.longNameFrench, a.longNameDutch
from cte a
join cte b on b.id = a.id
join cte c on c.id = b.id
where c.name = 'ptref'
and b.name = 'ptrefColumn'
and a.name = 'ptcar'
and c.id = 512
and a.validFromDate <= date '2001-01-01'
and a.validToDate >= date '2001-01-01'
and b.validFromDate <= date '2001-01-01'
and b.validToDate >= date '2001-01-01'
and c.validFromDate <= date '2001-01-01'
and c.validToDate >= date '2001-01-01';

LONGNAMEFRENCH                                               LONGNAMEDUTCH                                               
------------------------------------------------------------ ------------------------------------------------------------
Jean Dupont                                                  Jan Jansen                                                  

进行如下选择(或创建视图):

CREATE VIEW ptcar AS
SELECT Id, LongNameFrench, LongNameDutch,
    TO_DATE(x.ValidFromDate, 'YYYY-MM-DD') as ValidFromDate,
    ...
FROM XML_Infrastructure,
    XMLTABLE(
        '$d/*:ptcars/*:ptcar'
        PASSING XMLTYPE(XML_Infrastructure.XML_RAW) as "d"
        COLUMNS
            Id              VARCHAR2(10)    PATH    '@*:id',
            LongNameFrench  VARCHAR2(60)    PATH    '@*:longNameFrench',
            LongNameDutch   VARCHAR2(60)    PATH    '@*:longNameDutch',
            ValidFromDate   VARCHAR2(10)    PATH    '@*:validFromDate',
            ValidToDate     VARCHAR2(10)    PATH    '@*:validToDate'
    ) as x;

CREATE VIEW ptrefColumn AS
SELECT Id,
    TO_DATE(x.ValidFromDate, 'YYYY-MM-DD') as ValidFromDate,
    ...
FROM XML_Infrastructure,
XMLTABLE(
    '$d/*:ptrefColumns/*:ptrefColumn'
    PASSING XMLTYPE(XML_Infrastructure.XML_RAW) as "d"
    COLUMNS
        Id              VARCHAR2(10)    PATH    '@*:id',
        ValidFromDate   VARCHAR2(10)    PATH    '@*:validFromDate',
        ValidToDate     VARCHAR2(10)    PATH    '@*:validToDate'
) as x

之后,您可以按照您的问题直接加入他们。

注意,为什么将XML_RAW存储为CLOB而不是XMLTYPE

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM