How to query for Xml values and attributes from table in SQL Server?

前端 未结 4 1190
野趣味
野趣味 2020-11-30 21:57

I have a table that contains a Xml column:

SELECT * 
FROM Sqm

\"enter

相关标签:
4条回答
  • 2020-11-30 22:08

    Actually you're close to your goal, you just need to use nodes() method to split your rows and then get values:

    select
        s.SqmId,
        m.c.value('@id', 'varchar(max)') as id,
        m.c.value('@type', 'varchar(max)') as type,
        m.c.value('@unit', 'varchar(max)') as unit,
        m.c.value('@sum', 'varchar(max)') as [sum],
        m.c.value('@count', 'varchar(max)') as [count],
        m.c.value('@minValue', 'varchar(max)') as minValue,
        m.c.value('@maxValue', 'varchar(max)') as maxValue,
        m.c.value('.', 'nvarchar(max)') as Value,
        m.c.value('(text())[1]', 'nvarchar(max)') as Value2
    from sqm as s
        outer apply s.data.nodes('Sqm/Metrics/Metric') as m(c)
    

    sql fiddle demo

    0 讨论(0)
  • 2020-11-30 22:25

    I don't understand why some people are suggesting using cross apply or outer apply to convert the xml into a table of values. For me, that just brought back way too much data.

    Here's my example of how you'd create an xml object, then turn it into a table.

    (I've added spaces in my xml string, just to make it easier to read.)

    DECLARE @str nvarchar(2000)
    
    SET @str = ''
    SET @str = @str + '<users>'
    SET @str = @str + '  <user>'
    SET @str = @str + '     <firstName>Mike</firstName>'
    SET @str = @str + '     <lastName>Gledhill</lastName>'
    SET @str = @str + '     <age>31</age>'
    SET @str = @str + '  </user>'
    SET @str = @str + '  <user>'
    SET @str = @str + '     <firstName>Mark</firstName>'
    SET @str = @str + '     <lastName>Stevens</lastName>'
    SET @str = @str + '     <age>42</age>'
    SET @str = @str + '  </user>'
    SET @str = @str + '  <user>'
    SET @str = @str + '     <firstName>Sarah</firstName>'
    SET @str = @str + '     <lastName>Brown</lastName>'
    SET @str = @str + '     <age>23</age>'
    SET @str = @str + '  </user>'
    SET @str = @str + '</users>'
    
    DECLARE @xml xml
    SELECT @xml = CAST(CAST(@str AS VARBINARY(MAX)) AS XML) 
    
    --  Iterate through each of the "users\user" records in our XML
    SELECT 
        x.Rec.query('./firstName').value('.', 'nvarchar(2000)') AS 'FirstName',
        x.Rec.query('./lastName').value('.', 'nvarchar(2000)') AS 'LastName',
        x.Rec.query('./age').value('.', 'int') AS 'Age'
    FROM @xml.nodes('/users/user') as x(Rec)
    

    And here's the output:

    0 讨论(0)
  • 2020-11-30 22:26

    I've been trying to do something very similar but not using the nodes. However, my xml structure is a little different.

    You have it like this:

    <Metrics>
        <Metric id="TransactionCleanupThread.RefundOldTrans" type="timer" ...>
    

    If it were like this instead:

    <Metrics>
        <Metric>
            <id>TransactionCleanupThread.RefundOldTrans</id>
            <type>timer</type>
            .
            .
            .
    

    Then you could simply use this SQL statement.

    SELECT
        Sqm.SqmId,
        Data.value('(/Sqm/Metrics/Metric/id)[1]', 'varchar(max)') as id,
        Data.value('(/Sqm/Metrics/Metric/type)[1]', 'varchar(max)') AS type,
        Data.value('(/Sqm/Metrics/Metric/unit)[1]', 'varchar(max)') AS unit,
        Data.value('(/Sqm/Metrics/Metric/sum)[1]', 'varchar(max)') AS sum,
        Data.value('(/Sqm/Metrics/Metric/count)[1]', 'varchar(max)') AS count,
        Data.value('(/Sqm/Metrics/Metric/minValue)[1]', 'varchar(max)') AS minValue,
        Data.value('(/Sqm/Metrics/Metric/maxValue)[1]', 'varchar(max)') AS maxValue,
        Data.value('(/Sqm/Metrics/Metric/stdDeviation)[1]', 'varchar(max)') AS stdDeviation,
    FROM Sqm
    

    To me this is much less confusing than using the outer apply or cross apply.

    I hope this helps someone else looking for a simpler solution!

    0 讨论(0)
  • 2020-11-30 22:30

    use value instead of query (must specify index of node to return in the XQuery as well as passing the sql data type to return as the second parameter):

    select
        xt.Id
        , x.m.value( '@id[1]', 'varchar(max)' ) MetricId
    from
        XmlTest xt
        cross apply xt.XmlData.nodes( '/Sqm/Metrics/Metric' ) x(m)
    
    0 讨论(0)
提交回复
热议问题