如何在 SQL 查询中的 XML 标记之间 select 值
How to select values between a XML tag in SQL Query
我有一个 table,其中 CLOB 列存储一个 XML。 XML 的结构不可读。我想在 <DOMAINID>
这样的几个标签之间获取值;示例如下所示。
XML:
<ID>
<DOMAIN>IND<DOMAIN>
<DOMAINID>112AC<DOMAINID>
<ID>
<GROUP>
<GP>ASIA<GP>
<RSN>GOOD<RSN>
<GROUP>
我正在使用这个:
SELECT REGEXP_REPLACE(COL,'^.*<DOMAINID>(.*)</DOMAINID>.*$','',1,0,'mn') col1 FROM tab;
预期结果:
112AC
实际XML:
<?xml version="1.0" encoding="US-ASCII"?>
<GML:GMMessage
xmlns:GML="GML"
xmlns:GMLType="GML.Type"
xsi:schemaLocation="GML ../schema/gml..xsd" SchemaVersion="9.8">
<BusinessHdr>
<busHdr:BusObjectType>ABC</busHdr:BusObjectType>
<busHdr:BusObjectOwner>HDHDH</busHdr:BusObjectOwner>
<busHdr:BusObjectId>DJHDAHDAJHDA</busHdr:BusObjectId>
<busHdr:BusObjectVersion>1</busHdr:BusObjectVersion>
</BusinessHdr>
<Transaction>
<GenericEvent>NEW</GenericEvent>
<Group>
<GroupId>3424234</GroupId>
<Reason>MANUAL</Reason>
</Group>
< xsi:type="mm:MMIam">
<Id>
<Domain>ssdsgdsg</Domain>
<DomainId>123456ACC</DomainId>
<Version>1</Version>
</Id>
<Date>2021-02-01</Date>
</Transaction>
</GML:GMMessage>
很高兴看到你用你的方法思考...
建议查看此工具(如果您没有类似的工具)来帮助您使用正则表达式https://regexr.com/,对我帮助很大。
你 SQL 看起来是正确的(使用多行的“m”和“n”标志),但不确定你的 XML 是否输入错误,因为你是正则表达式字符串在您粘贴的 XML 上不起作用,但如果它是 XML.
我确实让它起作用了
您的 SQL 当前的输出是什么?您可能需要使用 </code> 代替 <code>
.
我也建议
- 也许还会转义您的正斜杠,因为这可能是您的罪魁祸首。
- 为您的捕获添加更多特异性,以防止您的搜索过于贪婪。
SELECT REGEXP_REPLACE(COL,'^.*<DOMAINID>([0-9A-z]+)<\/DOMAINID>.*$','',1,0,'mn') col1 FROM tab;
不要使用正则表达式解析XML;使用合适的 XML 解析器。
但是,您的格式不正确 XML,因为它缺少根元素,并且您在所有结束标记中都缺少 /
;所以你首先需要修复你的 XML 并给它一个根元素,然后你可以使用 XML 解析器解析它。
SELECT x.*
FROM table_name t
CROSS APPLY XMLTABLE(
'//root'
PASSING XMLTYPE( '<root>' || t.data || '</root>' )
COLUMNS
domain VARCHAR2(10) PATH './ID/DOMAIN',
domainid VARCHAR2(10) PATH './ID/DOMAINID',
gp VARCHAR2(50) PATH './GROUP/GP',
rsn VARCHAR2(50) PATH './GROUP/RSN'
) x
其中,对于示例数据:
CREATE TABLE table_name ( data ) AS
SELECT '<ID>
<DOMAIN>IND</DOMAIN>
<DOMAINID>112AC</DOMAINID>
</ID>
<GROUP>
<GP>ASIA</GP>
<RSN>GOOD</RSN>
</GROUP>' FROM DUAL
输出:
DOMAIN | DOMAINID | GP | RSN
:----- | :------- | :--- | :---
IND | 112AC | ASIA | GOOD
如果您只想要一个值,那么您可以使用 XMLQUERY
:
SELECT XMLQUERY(
'/root/ID/DOMAINID/text()'
PASSING XMLTYPE( '<root>'||data||'</root>' )
RETURNING CONTENT
) AS domainid
FROM table_name
输出:
| DOMAINID |
| :------- |
| 112AC |
db<>fiddle here
更新
我假设您的 XML 还定义了 xsi
和 busHdr
名称空间(如果没有,那么 Oracle 将无法解析 XML因为它不知道那些名称空间是什么);那会给你这个样本数据:
CREATE TABLE table_name ( data ) AS
SELECT '<?xml version="1.0" encoding="US-ASCII"?>
<GML:GMMessage
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:GML="GML"
xmlns:busHdr="busHdr"
xmlns:GMLType="GML.Type"
xsi:schemaLocation="GML ../schema/gml.xsd busHdr ../schema/bushdr.xsd"
SchemaVersion="9.8">
<BusinessHdr>
<busHdr:BusObjectType>ABC</busHdr:BusObjectType>
<busHdr:BusObjectOwner>HDHDH</busHdr:BusObjectOwner>
<busHdr:BusObjectId>DJHDAHDAJHDA</busHdr:BusObjectId>
<busHdr:BusObjectVersion>1</busHdr:BusObjectVersion>
</BusinessHdr>
<Transaction>
<GenericEvent>NEW</GenericEvent>
<Group>
<GroupId>3424234</GroupId>
<Reason>MANUAL</Reason>
</Group>
<Id>
<Domain>ssdsgdsg</Domain>
<DomainId>123456ACC</DomainId>
<Version>1</Version>
</Id>
<Date>2021-02-01</Date>
</Transaction>
</GML:GMMessage>' FROM DUAL
然后,您只需添加您正在使用的命名空间并将路径更新到新的(区分大小写的)位置:
SELECT x.*
FROM table_name t
CROSS APPLY XMLTABLE(
XMLNAMESPACES( 'GML' AS "GML" ),
'//GML:GMMessage/Transaction'
PASSING XMLTYPE( t.data )
COLUMNS
domain VARCHAR2(10) PATH './Id/Domain',
domainid VARCHAR2(10) PATH './Id/DomainId',
version NUMBER(3,0) PATH './Id/Version',
groupid VARCHAR2(50) PATH './Group/GroupId',
reason VARCHAR2(50) PATH './Group/Reason',
dt DATE PATH './Date'
) x
输出:
DOMAIN | DOMAINID | VERSION | GROUPID | REASON | DT
:------- | :-------- | ------: | :------ | :----- | :--------
ssdsgdsg | 123456ACC | 1 | 3424234 | MANUAL | 01-FEB-21
db<>fiddle here
我有一个 table,其中 CLOB 列存储一个 XML。 XML 的结构不可读。我想在 <DOMAINID>
这样的几个标签之间获取值;示例如下所示。
XML:
<ID>
<DOMAIN>IND<DOMAIN>
<DOMAINID>112AC<DOMAINID>
<ID>
<GROUP>
<GP>ASIA<GP>
<RSN>GOOD<RSN>
<GROUP>
我正在使用这个:
SELECT REGEXP_REPLACE(COL,'^.*<DOMAINID>(.*)</DOMAINID>.*$','',1,0,'mn') col1 FROM tab;
预期结果:
112AC
实际XML:
<?xml version="1.0" encoding="US-ASCII"?>
<GML:GMMessage
xmlns:GML="GML"
xmlns:GMLType="GML.Type"
xsi:schemaLocation="GML ../schema/gml..xsd" SchemaVersion="9.8">
<BusinessHdr>
<busHdr:BusObjectType>ABC</busHdr:BusObjectType>
<busHdr:BusObjectOwner>HDHDH</busHdr:BusObjectOwner>
<busHdr:BusObjectId>DJHDAHDAJHDA</busHdr:BusObjectId>
<busHdr:BusObjectVersion>1</busHdr:BusObjectVersion>
</BusinessHdr>
<Transaction>
<GenericEvent>NEW</GenericEvent>
<Group>
<GroupId>3424234</GroupId>
<Reason>MANUAL</Reason>
</Group>
< xsi:type="mm:MMIam">
<Id>
<Domain>ssdsgdsg</Domain>
<DomainId>123456ACC</DomainId>
<Version>1</Version>
</Id>
<Date>2021-02-01</Date>
</Transaction>
</GML:GMMessage>
很高兴看到你用你的方法思考...
建议查看此工具(如果您没有类似的工具)来帮助您使用正则表达式https://regexr.com/,对我帮助很大。
你 SQL 看起来是正确的(使用多行的“m”和“n”标志),但不确定你的 XML 是否输入错误,因为你是正则表达式字符串在您粘贴的 XML 上不起作用,但如果它是 XML.
我确实让它起作用了您的 SQL 当前的输出是什么?您可能需要使用 </code> 代替 <code>
.
我也建议
- 也许还会转义您的正斜杠,因为这可能是您的罪魁祸首。
- 为您的捕获添加更多特异性,以防止您的搜索过于贪婪。
SELECT REGEXP_REPLACE(COL,'^.*<DOMAINID>([0-9A-z]+)<\/DOMAINID>.*$','',1,0,'mn') col1 FROM tab;
不要使用正则表达式解析XML;使用合适的 XML 解析器。
但是,您的格式不正确 XML,因为它缺少根元素,并且您在所有结束标记中都缺少 /
;所以你首先需要修复你的 XML 并给它一个根元素,然后你可以使用 XML 解析器解析它。
SELECT x.*
FROM table_name t
CROSS APPLY XMLTABLE(
'//root'
PASSING XMLTYPE( '<root>' || t.data || '</root>' )
COLUMNS
domain VARCHAR2(10) PATH './ID/DOMAIN',
domainid VARCHAR2(10) PATH './ID/DOMAINID',
gp VARCHAR2(50) PATH './GROUP/GP',
rsn VARCHAR2(50) PATH './GROUP/RSN'
) x
其中,对于示例数据:
CREATE TABLE table_name ( data ) AS
SELECT '<ID>
<DOMAIN>IND</DOMAIN>
<DOMAINID>112AC</DOMAINID>
</ID>
<GROUP>
<GP>ASIA</GP>
<RSN>GOOD</RSN>
</GROUP>' FROM DUAL
输出:
DOMAIN | DOMAINID | GP | RSN :----- | :------- | :--- | :--- IND | 112AC | ASIA | GOOD
如果您只想要一个值,那么您可以使用 XMLQUERY
:
SELECT XMLQUERY(
'/root/ID/DOMAINID/text()'
PASSING XMLTYPE( '<root>'||data||'</root>' )
RETURNING CONTENT
) AS domainid
FROM table_name
输出:
| DOMAINID | | :------- | | 112AC |
db<>fiddle here
更新
我假设您的 XML 还定义了 xsi
和 busHdr
名称空间(如果没有,那么 Oracle 将无法解析 XML因为它不知道那些名称空间是什么);那会给你这个样本数据:
CREATE TABLE table_name ( data ) AS
SELECT '<?xml version="1.0" encoding="US-ASCII"?>
<GML:GMMessage
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:GML="GML"
xmlns:busHdr="busHdr"
xmlns:GMLType="GML.Type"
xsi:schemaLocation="GML ../schema/gml.xsd busHdr ../schema/bushdr.xsd"
SchemaVersion="9.8">
<BusinessHdr>
<busHdr:BusObjectType>ABC</busHdr:BusObjectType>
<busHdr:BusObjectOwner>HDHDH</busHdr:BusObjectOwner>
<busHdr:BusObjectId>DJHDAHDAJHDA</busHdr:BusObjectId>
<busHdr:BusObjectVersion>1</busHdr:BusObjectVersion>
</BusinessHdr>
<Transaction>
<GenericEvent>NEW</GenericEvent>
<Group>
<GroupId>3424234</GroupId>
<Reason>MANUAL</Reason>
</Group>
<Id>
<Domain>ssdsgdsg</Domain>
<DomainId>123456ACC</DomainId>
<Version>1</Version>
</Id>
<Date>2021-02-01</Date>
</Transaction>
</GML:GMMessage>' FROM DUAL
然后,您只需添加您正在使用的命名空间并将路径更新到新的(区分大小写的)位置:
SELECT x.*
FROM table_name t
CROSS APPLY XMLTABLE(
XMLNAMESPACES( 'GML' AS "GML" ),
'//GML:GMMessage/Transaction'
PASSING XMLTYPE( t.data )
COLUMNS
domain VARCHAR2(10) PATH './Id/Domain',
domainid VARCHAR2(10) PATH './Id/DomainId',
version NUMBER(3,0) PATH './Id/Version',
groupid VARCHAR2(50) PATH './Group/GroupId',
reason VARCHAR2(50) PATH './Group/Reason',
dt DATE PATH './Date'
) x
输出:
DOMAIN | DOMAINID | VERSION | GROUPID | REASON | DT :------- | :-------- | ------: | :------ | :----- | :-------- ssdsgdsg | 123456ACC | 1 | 3424234 | MANUAL | 01-FEB-21
db<>fiddle here