简体   繁体   English

将所有子节点作为列从SQL Server中的XML返回

[英]Returning all child nodes as columns from XML in Sql Server

I am doing the following to select nodes from an XML string, the first part is just to show you what I'm selecting from. 我正在执行以下操作以从XML字符串中选择节点,第一部分只是向您展示我要选择的内容。

The issue is I want to do this for various different XML columns and I'd like to not have to specify the node name for each column in my select, is there a way to select all nodes as columns automatically or even a cursor using count? 问题是我想对各种不同的XML列执行此操作,并且我不想在我的选择中为每个列指定节点名,有没有一种方法可以自动选择所有节点作为列,甚至可以使用count选择一个游标?

DECLARE @MyXML XML
SET @MyXML = (SELECT 
            CAST (
        '<AllowAdd>N</AllowAdd>
        <Allowed>NUMSEG</Allowed>
        <AllSegmentsEqualValue>N</AllSegmentsEqualValue>
        <ClusterLevelSA>Y</ClusterLevelSA>
        <ClusterLevelPremium>Y</ClusterLevelPremium>
        <AllowAssignedAndInTrust>N</AllowAssignedAndInTrust>
        <MinSegments>1</MinSegments>
        <MaxSegments>100</MaxSegments>
        <DefaultSegments>10</DefaultSegments>
        <RoundPremiumsTo>2</RoundPremiumsTo>
        <TaxDeferredAllowance>0.05</TaxDeferredAllowance>
        <HigherTaxValueBands>HTVB</HigherTaxValueBands>
        <NumberYearsCalculationType>NONFIN</NumberYearsCalculationType>
        <OnShore>POLICY</OnShore>
        <OffShore>NONFIN</OffShore>'as XML) as x)

        SELECT 
        Data.Col.value('(/AllowAdd)[1]','Varchar(10)') as [Allow Addition of]
        ,Data.Col.value('(/Allowed)[1]','Varchar(10)') as [Allowed]
        ,Data.Col.value('(/MinSegments)[1]','Int') as [Min Segments]
        ,Data.Col.value('(/MaxSegments)[1]','Int') as [Max Segments]
        ,Data.Col.value('(/DefaultSegments)[1]','Int') as [Default Segments]
        ,Data.Col.value('(/RoundPremiumsTo)[1]','Int') as [Round Premiums To]
        ,Data.Col.value('(/AllSegmentsEqualValue)[1]','Varchar(10)') as [All Segments Equal Value]
        --,Data.Col.value('(/TaxDeferredAllowance)[1]','Varchar(10)') as [Tax Deferred Allowance]
        ,Data.Col.value('(/HigherTaxValueBands)[1]','Varchar(10)') as [Higher Tax Value Bands]
        ,Data.Col.value('(/NumberYearsCalculationType)[1]','Varchar(10)') as [Number Years Calculation Type]
        ,Data.Col.value('(/OnShore)[1]','Varchar(10)') as [OnShore]
        ,Data.Col.value('(/OffShore)[1]','Varchar(10)') as [OffShore]
        FROM @MyXML.nodes('/OffShore') AS Data(Col)

I hope, this is what you are waiting for :) 我希望,这就是您在等待的内容:)

DECLARE @MyXML XML
SET @MyXML = (SELECT 
            CAST (
        '<AllowAdd>N</AllowAdd>
        <Allowed>NUMSEG</Allowed>
        <AllSegmentsEqualValue>N</AllSegmentsEqualValue>
        <ClusterLevelSA>Y</ClusterLevelSA>
        <ClusterLevelPremium>Y</ClusterLevelPremium>
        <AllowAssignedAndInTrust>N</AllowAssignedAndInTrust>
        <MinSegments>1</MinSegments>
        <MaxSegments>100</MaxSegments>
        <DefaultSegments>10</DefaultSegments>
        <RoundPremiumsTo>2</RoundPremiumsTo>
        <TaxDeferredAllowance>0.05</TaxDeferredAllowance>
        <HigherTaxValueBands>HTVB</HigherTaxValueBands>
        <NumberYearsCalculationType>NONFIN</NumberYearsCalculationType>
        <OnShore>POLICY</OnShore>
        <OffShore>NONFIN</OffShore>'as XML) as x)

DECLARE @Output nvarchar(max) = N''
DECLARE @PivotList nvarchar(max)


SELECT 
    @PivotList = COALESCE(@PivotList + ', ', N'') + N'[' + XC.value('local-name(.)', 'varchar(100)') + N']'
FROM 
    @MyXML.nodes('/*') AS XT(XC)

SET @Output = N'SELECT 
    '+@PivotList+N'
FROM
(
    SELECT 
       ColName = XC.value(''local-name(.)'', ''nvarchar(100)''),
       ColValue = ISNULL(NULLIF(CONVERT(nvarchar(max),XC.query(''./*'')),''''),XC.value(''.'',''nvarchar(max)''))
    FROM 
       @MyXML.nodes(''/*'') AS XT(XC)
) AS s
PIVOT
(
    MAX(ColValue)
    FOR ColName IN ('+@PivotList+N')
) AS t;'

EXEC sp_executesql @Output, N'@MyXml xml', @MyXML = @MyXML;

Given your input XML, you can try to use this: 给定您输入的XML,您可以尝试使用此方法:

SELECT 
    ColName = XC.value('local-name(.)', 'varchar(100)'),
    ColValue = xc.value('(.)[1]', 'varchar(100)')
FROM 
    @MyXML.nodes('/*') AS XT(XC)

This will output each XML element found under the root - its name and value - as a list: 这会将在根目录下找到的每个XML元素(其名称和值)输出为列表:

在此处输入图片说明

Of course, since it's a very generic approach, you cannot really define the proper datatypes for each columns in the second xc.value() - you basically get everything as a string. 当然,由于这是一种非常通用的方法,因此您无法真正为第二个xc.value()中的每一列定义正确的数据类型-您基本上将所有内容作为字符串获取。

Using a cursor to build a SELECT statement and sp_executesql to execute it! 使用游标构建SELECT语句,然后使用sp_executesql执行该语句!

    DECLARE @MyXML XML
    DECLARE @FieldName VARCHAR(MAX)
    DECLARE @SELECT_TEXT NVARCHAR(MAX)

    SET @MyXML = (SELECT 
                    CAST (
                '<AllowAdd>N</AllowAdd>
    <Allowed>NUMSEG</Allowed>
    <AllSegmentsEqualValue>N</AllSegmentsEqualValue>
    <ClusterLevelSA>Y</ClusterLevelSA>
    <ClusterLevelPremium>Y</ClusterLevelPremium>
    <AllowAssignedAndInTrust>N</AllowAssignedAndInTrust>
    <MinSegments>1</MinSegments>
    <MaxSegments>100</MaxSegments>
    <DefaultSegments>10</DefaultSegments>
    <RoundPremiumsTo>2</RoundPremiumsTo>
    <TaxDeferredAllowance>0.05</TaxDeferredAllowance>
    <HigherTaxValueBands>HTVB</HigherTaxValueBands>
    <NumberYearsCalculationType>NONFIN</NumberYearsCalculationType>
    <OnShore>POLICY</OnShore>
    <OffShore>NONFIN</OffShore>
    '
                    as XML) as x)


    SET @SELECT_TEXT = 'SELECT '

    DECLARE xml_cursor CURSOR
        FOR SELECT Data.Col.value( 'fn:local-name(.)', 'VARCHAR(MAX)' ) FROM @MyXML.nodes('/*') AS Data(Col)

    open xml_cursor
    While 1 = 1
    BEGIN
        fetch next from xml_cursor into @FieldName

        if @@fetch_status <> 0
        begin
                break
        end

        SET @SELECT_TEXT = @SELECT_TEXT + 'Data.Col.value(''(/' + @FieldName + ')[1]'',''Varchar(MAX)'') as [' + @FieldName + ']' + ', '

    END

    close xml_cursor 
    deallocate xml_cursor 

    SET @SELECT_TEXT = SUBSTRING( @SELECT_TEXT,0, LEN(@SELECT_TEXT) ) + 'FROM @MyXML.nodes(''/OffShore'') AS Data(Col)'

    EXECUTE sp_executesql @SELECT_TEXT, N'@MyXML XML', @MyXML = @MyXML

As previously mentioned in another comment the drawback is not having column types but it's for a report style query so strings is ok. 正如前面在另一条评论中提到的,缺点是没有列类型,但是它是用于报表样式查询的,因此字符串可以。

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

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