在包含 XML 但未存储为 XML 类型的列中查询 XML XPATH

Query XML XPATH in column containing XML but not stored as XML type

我正在处理的数据库中有一列包含 XML,但存储为 varchar。我可以将列 CAST() 设置为 XML,但不清楚如何使用 XPATH 或其他方式从该列中获取任何内容。

EXTRACT() 似乎只针对 MYSQL,而 .value() 在我试过的任何形式下都不起作用。我希望我只是在这里做错了。

如果有特定于版本的解决方案,查询 @@VERSION 会得到以下信息:

Microsoft SQL Server 2012 (SP4-GDR) (KB4583465) - 11.0.7507.2 (X64) Nov 1 2020 00:48:37 Copyright (c) Microsoft Corporation Enterprise Edition: Core-based Licensing (64-bit) on Windows NT 6.3 (Build 9600: ) (Hypervisor)

下面是我正在使用的 XML 的简化示例。非常感谢任何有关如何为任何给定元素提取值的示例。

<?xml version="1.0" encoding="UTF-8"?>
<ExampleXML>
   <Version></Version>
   <NameSpace></NameSpace>
   <ClientID></ClientID>
   <ClientName></ClientName>
   <ShipToInfo>
      <Name></Name>
      <Address1></Address1>
      <Address2 />
      <City></City>
      <State></State>
      <Postal></Postal>
      <Country></Country>
      <Phone></Phone>
      <Fax></Fax>
      <EIdType />
      <EId></EId>
   </ShipToInfo>
   <BillToInfo>
      <Name></Name>
      <Address1></Address1>
      <Address2 />
      <City></City>
      <State></State>
      <Postal></Postal>
      <Country></Country>
      <Phone></Phone>
      <Fax></Fax>
      <EIdType />
      <EId></EId>
   </BillToInfo>
</ExampleXML>

编辑: .value()

的示例
SELECT CAST(CONTENT AS xml).value('(/ExampleXML/ShipToInfo/@EId)[1]', 'int')

结果列包含 NULL

编辑 2: 看起来适合我的最终版本如下:

SELECT top 1 ET.*, t2.c.value('EId[1]', 'varchar(max)') AS store_num
FROM example_table ET
    OUTER APPLY (SELECT CAST(ET.CONTENT AS xml) AS realxml) t1
    OUTER APPLY t1.realxml.nodes('//ExampleXML/ShipToInfo') AS t2(c);

请尝试以下解决方案。

对于具有 XML 数据的列,最好使用 XML 数据类型。

从 SQL Server 2005 开始可用。

SQL

-- DDL and sample data population, start
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, Content NVARCHAR(MAX));
INSERT INTO @tbl (Content) VALUES
(N'<ExampleXML>
   <Version></Version>
   <NameSpace></NameSpace>
   <ClientID></ClientID>
   <ClientName></ClientName>
   <ShipToInfo>
      <Name>Paul Braddock</Name>
      <Address1>3851 SE 52nd St.</Address1>
      <Address2 />
      <City>Ottawa</City>
      <State></State>
      <Postal>12345</Postal>
      <Country>Canada</Country>
      <Phone>123-456-7890</Phone>
      <Fax></Fax>
      <EIdType>Alien</EIdType>
      <EId>18</EId>
   </ShipToInfo>
   <BillToInfo>
      <Name></Name>
      <Address1></Address1>
      <Address2 />
      <City></City>
      <State></State>
      <Postal></Postal>
      <Country></Country>
      <Phone></Phone>
      <Fax></Fax>
      <EIdType />
      <EId></EId>
   </BillToInfo>
</ExampleXML>');
-- DDL and sample data population, end

SELECT t.ID
    , x.value('(Name/text())[1]', 'VARCHAR(20)') AS [Name]
    , x.value('(Address1/text())[1]', 'VARCHAR(20)') AS Address1
    , x.value('(City/text())[1]', 'VARCHAR(20)') AS City
    , x.value('(Country/text())[1]', 'VARCHAR(20)') AS Country
FROM @tbl AS t
CROSS APPLY (SELECT TRY_CAST(content AS XML)) AS t1(c)
CROSS APPLY c.nodes('/ExampleXML/ShipToInfo') AS t2(x);

输出

+----+---------------+------------------+--------+---------+
| ID |     Name      |     Address1     |  City  | Country |
+----+---------------+------------------+--------+---------+
|  1 | Paul Braddock | 3851 SE 52nd St. | Ottawa | Canada  |
+----+---------------+------------------+--------+---------+