【问题标题】:Extracting a value from an XML column in SQL Server从 SQL Server 中的 XML 列中提取值
【发布时间】:2020-09-21 01:44:19
【问题描述】:

我正在尝试从以下 XML 中提取 FirstNameLastName 中存在的数据值,该 XML 在 SQL Server 表的列中作为字符串存在。

<ns6:Account xmlns="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.contactmodel" xmlns:ns2="http://example.com/pc/gx/abc.pc.dm.gx.shared.location.addressmodel" xmlns:ns4="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.officialidmodel" xmlns:ns3="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.contactaddressmodel" xmlns:ns6="http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc" xmlns:ns5="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.accountcontactmodel" xmlns:ns8="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.usermodel" xmlns:ns7="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.historymodel" xmlns:ns13="http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc" xmlns:ns9="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.activitymodel" xmlns:ns12="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.industrycodemodel" xmlns:ns11="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.documentmodel" xmlns:ns10="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.groupmodel" xmlns:ns17="http://example.com/pc/gx/abc.pc.dm.gx.shared.producer.producercodemodel" xmlns:ns16="http://example.com/pc/gx/abc.pc.dm.gx.shared.producer.accountproducercodemodel" xmlns:ns15="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.notemodel" xmlns:ns14="http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc">
    <ns6:AccountHolderContact>
        <entity-Person>
            <DateOfBirth>999-01-02T12:00:00-05:00</DateOfBirth>
            <FirstName>ABC</FirstName>
            <Gender>F</Gender>
            <LastName>ABC</LastName>
            <LicenseNumber>9999-9999-9999</LicenseNumber>
            <LicenseState>AA</LicenseState>
            <MaritalStatus>S</MaritalStatus>
            <OrganizationType_IC>individual</OrganizationType_IC>
        </entity-Person>
        <HomePhone>9999999999</HomePhone>
        <PrimaryAddress>
            <ns2:AddressLine1>99 ABC St</ns2:AddressLine1>
            <ns2:AddressType>home</ns2:AddressType>
            <ns2:City>AAA</ns2:City>
            <ns2:Country>AA</ns2:Country>
            <ns2:PostalCode>ABC MMM</ns2:PostalCode>
            <ns2:State>AA</ns2:State>
            <ns2:Subtype>Address</ns2:Subtype>
        </PrimaryAddress>
        <PublicID>1</PublicID>
        <Subtype>person</Subtype>
    </ns6:AccountHolderContact>
</ns6:Account>

这是我尝试过的查询:

select 
    application_id, accountID, 
    cast(payload as xml).value('(//*:Account//*:AccountHolderContact)[1]', 'varchar(max)') as FirstName
from
    [test1].[dbo].[test2]

此查询从 XML 节点 &lt;AccountHolderContact&gt; 返回所有子节点中的数据。

999-01-02T12:00:00-05:00ABCFABC9999-9999-9999AASIndividual999999999999 ABC SthomeAAAAAABC MMMAAAddress1Person

当我将查询更改为以下内容时,我的输出列 FirstName 中没有数据:

select 
    application_id, accountID, 
    cast(payload as xml).value('(//*:Account//*:AccountHolderContact/entity-Person/FirstName)[1]','varchar(max)') as FirstName
from
    [test1].[dbo].[test2]

我无法从AccountHolderContact 的子节点中提取是否有原因?如果没有,最简单的方法是什么?

【问题讨论】:

    标签: sql-server xml tsql xquery shred


    【解决方案1】:

    您的 XML 有多个命名空间 - 总共 17 个。只应考虑其中两个。由于性能原因,最好不要使用命名空间通配符。

    以下是如何分解您的 XML 并检索您需要的内容。

    SQL

    -- DDL and sample data population, start
    DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, payload NVARCHAR(MAX));
    INSERT INTO @tbl (payload) VALUES
    (N'<?xml version="1.0"?>
    <ns6:Account xmlns="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.contactmodel"
                 xmlns:ns2="http://example.com/pc/gx/abc.pc.dm.gx.shared.location.addressmodel"
                 xmlns:ns4="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.officialidmodel"
                 xmlns:ns3="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.contactaddressmodel"
                 xmlns:ns6="http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc"
                 xmlns:ns5="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.accountcontactmodel"
                 xmlns:ns8="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.usermodel"
                 xmlns:ns7="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.historymodel"
                 xmlns:ns13="http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc"
                 xmlns:ns9="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.activitymodel"
                 xmlns:ns12="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.industrycodemodel"
                 xmlns:ns11="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.documentmodel"
                 xmlns:ns10="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.groupmodel"
                 xmlns:ns17="http://example.com/pc/gx/abc.pc.dm.gx.shared.producer.producercodemodel"
                 xmlns:ns16="http://example.com/pc/gx/abc.pc.dm.gx.shared.producer.accountproducercodemodel"
                 xmlns:ns15="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.notemodel"
                 xmlns:ns14="http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc">
        <ns6:AccountHolderContact>
            <entity-Person>
                <DateOfBirth>999-01-02T12:00:00-05:00</DateOfBirth>
                <FirstName>ABC</FirstName>
                <Gender>F</Gender>
                <LastName>ABC</LastName>
                <LicenseNumber>9999-9999-9999</LicenseNumber>
                <LicenseState>AA</LicenseState>
                <MaritalStatus>S</MaritalStatus>
                <OrganizationType_IC>individual</OrganizationType_IC>
            </entity-Person>
            <HomePhone>9999999999</HomePhone>
            <PrimaryAddress>
                <ns2:AddressLine1>99 ABC St</ns2:AddressLine1>
                <ns2:AddressType>home</ns2:AddressType>
                <ns2:City>AAA</ns2:City>
                <ns2:Country>AA</ns2:Country>
                <ns2:PostalCode>ABC MMM</ns2:PostalCode>
                <ns2:State>AA</ns2:State>
                <ns2:Subtype>Address</ns2:Subtype>
            </PrimaryAddress>
            <PublicID>1</PublicID>
            <Subtype>person</Subtype>
        </ns6:AccountHolderContact>
    </ns6:Account>');
    -- DDL and sample data population, end
    
    ;WITH XMLNAMESPACES (DEFAULT 'http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.contactmodel'
        , 'http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc' AS ns14) ,rs AS
    (
       SELECT id, TRY_CAST(payload AS XML) AS xmldata
       FROM @tbl
    )
    SELECT ID
       , c.value('(FirstName/text())[1]','VARCHAR(50)') AS FirstName
       , c.value('(LastName/text())[1]','VARCHAR(50)') AS LastName
    FROM rs CROSS APPLY rs.xmldata.nodes('/ns14:Account/ns14:AccountHolderContact/entity-Person') AS t(c);
    

    输出

    +----+-----------+----------+
    | ID | FirstName | LastName |
    +----+-----------+----------+
    |  1 | ABC       | ABC      |
    +----+-----------+----------+
    

    【讨论】:

    • @PSA,很高兴听到建议的解决方案对您有用。请不要忘记将其标记为答案。
    【解决方案2】:

    假设XML只能包含1个AccountHolderContact实体(或类似实体),那么可以使用WITHXMLSPACES和XML运算符value来获取信息:

    DECLARE @XML xml = '<ns6:Account xmlns="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.contactmodel" xmlns:ns2="http://example.com/pc/gx/abc.pc.dm.gx.shared.location.addressmodel" xmlns:ns4="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.officialidmodel" xmlns:ns3="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.contactaddressmodel" xmlns:ns6="http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc" xmlns:ns5="http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.accountcontactmodel" xmlns:ns8="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.usermodel" xmlns:ns7="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.historymodel" xmlns:ns13="http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc" xmlns:ns9="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.activitymodel" xmlns:ns12="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.industrycodemodel" xmlns:ns11="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.documentmodel" xmlns:ns10="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.groupmodel" xmlns:ns17="http://example.com/pc/gx/abc.pc.dm.gx.shared.producer.producercodemodel" xmlns:ns16="http://example.com/pc/gx/abc.pc.dm.gx.shared.producer.accountproducercodemodel" xmlns:ns15="http://example.com/pc/gx/abc.pc.dm.gx.shared.general.notemodel" xmlns:ns14="http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc">
        <ns6:AccountHolderContact>
            <entity-Person>
                <DateOfBirth>999-01-02T12:00:00-05:00</DateOfBirth>
                <FirstName>ABC</FirstName>
                <Gender>F</Gender>
                <LastName>ABC</LastName>
                <LicenseNumber>9999-9999-9999</LicenseNumber>
                <LicenseState>AA</LicenseState>
                <MaritalStatus>S</MaritalStatus>
                <OrganizationType_IC>individual</OrganizationType_IC>
            </entity-Person>
            <HomePhone>9999999999</HomePhone>
            <PrimaryAddress>
                <ns2:AddressLine1>99 ABC St</ns2:AddressLine1>
                <ns2:AddressType>home</ns2:AddressType>
                <ns2:City>AAA</ns2:City>
                <ns2:Country>AA</ns2:Country>
                <ns2:PostalCode>ABC MMM</ns2:PostalCode>
                <ns2:State>AA</ns2:State>
                <ns2:Subtype>Address</ns2:Subtype>
            </PrimaryAddress>
            <PublicID>1</PublicID>
            <Subtype>person</Subtype>
        </ns6:AccountHolderContact>
    </ns6:Account>';
    
    WITH XMLNAMESPACES(DEFAULT 'http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.contactmodel', 'http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc' AS ns6)
    SELECT V.X.value('(ns6:Account/ns6:AccountHolderContact/entity-Person/FirstName/text())[1]','nvarchar(20)') AS FirstName,
           V.X.value('(ns6:Account/ns6:AccountHolderContact/entity-Person/LastName/text())[1]','nvarchar(20)') AS FirstName
    FROM(VALUES(@XML))V(X);
    

    但是,如果您的数据中可能有不止一个人,那么您可以使用 nodes 获取每人 1 行(这仍会带回具有相同样本数据的行)。如果AccountHolderContact 是重复项,它将如下所示:

    WITH XMLNAMESPACES(DEFAULT 'http://example.com/pc/gx/abc.pc.dm.gx.shared.contact.contactmodel', 'http://example.com/pc/gx/abc.pc.dm.gx.base.account.abc' AS ns6)
    SELECT A.AHC.value('(entity-Person/FirstName/text())[1]','nvarchar(20)') AS FirstName,
           A.AHC.value('(entity-Person/LastName/text())[1]','nvarchar(20)') AS FirstName
    FROM(VALUES(@XML))V(X)
        CROSS APPLY V.X.nodes('ns6:Account/ns6:AccountHolderContact')A(AHC);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      相关资源
      最近更新 更多