Oracle XMLTYPE 基于值和条件提取
Oracle XMLTYPE extract based on value and condition
SELECT * FROM v$version;
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
"CORE 12.1.0.2.0 Production"
TNS for Linux: Version 12.1.0.2.0 - Production
NLSRTL Version 12.1.0.2.0 - Production
我有 XML 的示例查询,如下所示:
with t(xml) as
(
select xmltype(
'<SSO_XML
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
TimeStamp="2020-08-05T21:57:23Z"
Target="Production"
Version="1.0"
TransactionIdentifier="PLAN_A"
SequenceNmbr="123456"
xmlns="http://www.w3.org/2001/XMLSchema">
<PlanCode PlanCodeCode="CHOICE">
<S_DAYS PCODE="P123">
<STUDENT>
<DIVISION Amount="150.05" Code="Flat" S_CODE="1" />
<DIVISION Amount="250.05" Code="Flat" S_CODE="2" />
</STUDENT>
</S_DAYS>
<S_DAYS PCODE="P1234">
<STUDENT>
<DIVISION Amount="150.05" Code="Flat" S_CODE="1" />
<DIVISION Amount="250.05" Code="Flat" S_CODE="2" />
</STUDENT>
</S_DAYS>
<S_DAYS PCODE="Child1">
<AdditonalFare>
<AdditonalFareAmount Amount="100"/>
</AdditonalFare>
</S_DAYS>
<S_DAYS PCODE="Child2">
<AdditonalFare>
<AdditonalFareAmount Amount="130"/>
</AdditonalFare>
</S_DAYS>
</PlanCode>
</SSO_XML>')
from dual
)
select h.PlanCodeCode
,b.*
from t
cross join
xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'/SSO_XML'
passing t.xml
columns PlanCodeCode varchar2(100) path './PlanCode/@PlanCodeCode',
attributes xmltype path './PlanCode'
) h
left join xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'PlanCode/S_DAYS/STUDENT/DIVISION'
passing h.attributes
columns node_level for ordinality
, amount number path '@Amount'
, pcode varchar2(10) path './../../@PCODE'
, child1_amount number path './../../@Amount[1]' --->Child1
, child2_amount number path './../../@Amount[2]' --->Child2
) b on 1=1;
XML 预期有 S_DAYS 节点与 STUDENT -> DIVISION ,我们从 XML.
中获取 Amount 值
有可选节点 S_DAYS S_DAYS PCODE="Child1" 或 PCODE="Child2"
当存在 Child1 或 Child2 的节点 PCODE 时,我们必须自己申请现有行。
实际结果:
预期结果:
任何帮助将不胜感激。
谢谢
你可以走回学生s_days
节点的兄弟姐妹:
select h.PlanCodeCode, b.amount, b.pcode, b.child1_amount, b.child2_amount
from t
cross join
xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'/SSO_XML'
passing t.xml
columns PlanCodeCode varchar2(100) path './PlanCode/@PlanCodeCode',
attributes xmltype path './PlanCode'
) h
left join xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'PlanCode/S_DAYS/STUDENT/DIVISION'
passing h.attributes
columns node_level for ordinality
, amount number path '@Amount'
, pcode varchar2(10) path './../../@PCODE'
, child1_amount number path './../../../S_DAYS[@PCODE="Child1"]/AdditonalFare/AdditonalFareAmount/@Amount'
, child2_amount number path './../../../S_DAYS[@PCODE="Child2"]/AdditonalFare/AdditonalFareAmount/@Amount'
) b on 1=1;
或者您可以从第一个 XMLTable 中获取 children,如果您即使没有学生节点也总是希望看到它们:
select h.PlanCodeCode, b.amount, b.pcode, h.child1_amount, h.child2_amount
from t
cross join
xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'/SSO_XML'
passing t.xml
columns PlanCodeCode varchar2(100) path './PlanCode/@PlanCodeCode',
attributes xmltype path './PlanCode',
child1_amount number path './PlanCode/S_DAYS[@PCODE="Child1"]/AdditonalFare/AdditonalFareAmount/@Amount',
child2_amount number path './PlanCode/S_DAYS[@PCODE="Child2"]/AdditonalFare/AdditonalFareAmount/@Amount'
) h
left join xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'PlanCode/S_DAYS/STUDENT/DIVISION'
passing h.attributes
columns node_level for ordinality
, amount number path '@Amount'
, pcode varchar2(10) path './../../@PCODE'
) b on 1=1;
顺便说一句,因为你在 12c 上,你可以使用 cross apply
和 outer apply
- 后者而不是带有虚拟 on 1=1
条件的外部连接。
select h.PlanCodeCode, b.amount, b.pcode, h.child1_amount, h.child2_amount
from t
cross apply
xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'/SSO_XML'
passing t.xml
columns PlanCodeCode varchar2(100) path './PlanCode/@PlanCodeCode',
attributes xmltype path './PlanCode',
child1_amount number path './PlanCode/S_DAYS[@PCODE="Child1"]/AdditonalFare/AdditonalFareAmount/@Amount',
child2_amount number path './PlanCode/S_DAYS[@PCODE="Child2"]/AdditonalFare/AdditonalFareAmount/@Amount'
) h
outer apply xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'PlanCode/S_DAYS/STUDENT/DIVISION'
passing h.attributes
columns node_level for ordinality
, amount number path '@Amount'
, pcode varchar2(10) path './../../@PCODE'
) b;
其中任何一个都得到与您的示例数据相同的结果:
PLANCODECODE | AMOUNT | PCODE | CHILD1_AMOUNT | CHILD2_AMOUNT
:----------- | -----: | :---- | ------------: | ------------:
CHOICE | 150.05 | P123 | 100 | 130
CHOICE | 250.05 | P123 | 100 | 130
CHOICE | 150.05 | P1234 | 100 | 130
CHOICE | 250.05 | P1234 | 100 | 130
SELECT * FROM v$version;
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
"CORE 12.1.0.2.0 Production"
TNS for Linux: Version 12.1.0.2.0 - Production
NLSRTL Version 12.1.0.2.0 - Production
我有 XML 的示例查询,如下所示:
with t(xml) as
(
select xmltype(
'<SSO_XML
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
TimeStamp="2020-08-05T21:57:23Z"
Target="Production"
Version="1.0"
TransactionIdentifier="PLAN_A"
SequenceNmbr="123456"
xmlns="http://www.w3.org/2001/XMLSchema">
<PlanCode PlanCodeCode="CHOICE">
<S_DAYS PCODE="P123">
<STUDENT>
<DIVISION Amount="150.05" Code="Flat" S_CODE="1" />
<DIVISION Amount="250.05" Code="Flat" S_CODE="2" />
</STUDENT>
</S_DAYS>
<S_DAYS PCODE="P1234">
<STUDENT>
<DIVISION Amount="150.05" Code="Flat" S_CODE="1" />
<DIVISION Amount="250.05" Code="Flat" S_CODE="2" />
</STUDENT>
</S_DAYS>
<S_DAYS PCODE="Child1">
<AdditonalFare>
<AdditonalFareAmount Amount="100"/>
</AdditonalFare>
</S_DAYS>
<S_DAYS PCODE="Child2">
<AdditonalFare>
<AdditonalFareAmount Amount="130"/>
</AdditonalFare>
</S_DAYS>
</PlanCode>
</SSO_XML>')
from dual
)
select h.PlanCodeCode
,b.*
from t
cross join
xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'/SSO_XML'
passing t.xml
columns PlanCodeCode varchar2(100) path './PlanCode/@PlanCodeCode',
attributes xmltype path './PlanCode'
) h
left join xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'PlanCode/S_DAYS/STUDENT/DIVISION'
passing h.attributes
columns node_level for ordinality
, amount number path '@Amount'
, pcode varchar2(10) path './../../@PCODE'
, child1_amount number path './../../@Amount[1]' --->Child1
, child2_amount number path './../../@Amount[2]' --->Child2
) b on 1=1;
XML 预期有 S_DAYS 节点与 STUDENT -> DIVISION ,我们从 XML.
中获取 Amount 值有可选节点 S_DAYS S_DAYS PCODE="Child1" 或 PCODE="Child2"
当存在 Child1 或 Child2 的节点 PCODE 时,我们必须自己申请现有行。
实际结果:
预期结果:
任何帮助将不胜感激。 谢谢
你可以走回学生s_days
节点的兄弟姐妹:
select h.PlanCodeCode, b.amount, b.pcode, b.child1_amount, b.child2_amount
from t
cross join
xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'/SSO_XML'
passing t.xml
columns PlanCodeCode varchar2(100) path './PlanCode/@PlanCodeCode',
attributes xmltype path './PlanCode'
) h
left join xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'PlanCode/S_DAYS/STUDENT/DIVISION'
passing h.attributes
columns node_level for ordinality
, amount number path '@Amount'
, pcode varchar2(10) path './../../@PCODE'
, child1_amount number path './../../../S_DAYS[@PCODE="Child1"]/AdditonalFare/AdditonalFareAmount/@Amount'
, child2_amount number path './../../../S_DAYS[@PCODE="Child2"]/AdditonalFare/AdditonalFareAmount/@Amount'
) b on 1=1;
或者您可以从第一个 XMLTable 中获取 children,如果您即使没有学生节点也总是希望看到它们:
select h.PlanCodeCode, b.amount, b.pcode, h.child1_amount, h.child2_amount
from t
cross join
xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'/SSO_XML'
passing t.xml
columns PlanCodeCode varchar2(100) path './PlanCode/@PlanCodeCode',
attributes xmltype path './PlanCode',
child1_amount number path './PlanCode/S_DAYS[@PCODE="Child1"]/AdditonalFare/AdditonalFareAmount/@Amount',
child2_amount number path './PlanCode/S_DAYS[@PCODE="Child2"]/AdditonalFare/AdditonalFareAmount/@Amount'
) h
left join xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'PlanCode/S_DAYS/STUDENT/DIVISION'
passing h.attributes
columns node_level for ordinality
, amount number path '@Amount'
, pcode varchar2(10) path './../../@PCODE'
) b on 1=1;
顺便说一句,因为你在 12c 上,你可以使用 cross apply
和 outer apply
- 后者而不是带有虚拟 on 1=1
条件的外部连接。
select h.PlanCodeCode, b.amount, b.pcode, h.child1_amount, h.child2_amount
from t
cross apply
xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'/SSO_XML'
passing t.xml
columns PlanCodeCode varchar2(100) path './PlanCode/@PlanCodeCode',
attributes xmltype path './PlanCode',
child1_amount number path './PlanCode/S_DAYS[@PCODE="Child1"]/AdditonalFare/AdditonalFareAmount/@Amount',
child2_amount number path './PlanCode/S_DAYS[@PCODE="Child2"]/AdditonalFare/AdditonalFareAmount/@Amount'
) h
outer apply xmltable(xmlnamespaces(default 'http://www.w3.org/2001/XMLSchema'),
'PlanCode/S_DAYS/STUDENT/DIVISION'
passing h.attributes
columns node_level for ordinality
, amount number path '@Amount'
, pcode varchar2(10) path './../../@PCODE'
) b;
其中任何一个都得到与您的示例数据相同的结果:
PLANCODECODE | AMOUNT | PCODE | CHILD1_AMOUNT | CHILD2_AMOUNT
:----------- | -----: | :---- | ------------: | ------------:
CHOICE | 150.05 | P123 | 100 | 130
CHOICE | 250.05 | P123 | 100 | 130
CHOICE | 150.05 | P1234 | 100 | 130
CHOICE | 250.05 | P1234 | 100 | 130