Sql server 如何在SQLServer中从表中查询Xml值和属性?

Sql server 如何在SQLServer中从表中查询Xml值和属性?,sql-server,xml,sql-server-2005,sql-server-2008-r2,sqlxml,Sql Server,Xml,Sql Server 2005,Sql Server 2008 R2,Sqlxml,我有一个包含Xml列的表: SELECT * FROM Sqm 一行的xml数据示例如下: <Sqm version="1.2"> <Metrics> <Metric id="TransactionCleanupThread.RecordUsedTransactionShift" type="timer" unit="µs" count="1" sum="21490" average="21490" minValue="73701"

我有一个包含
Xml
列的表:

SELECT * 
FROM Sqm

一行的
xml
数据示例如下:

<Sqm version="1.2">
  <Metrics>
    <Metric id="TransactionCleanupThread.RecordUsedTransactionShift" type="timer" unit="µs" count="1" sum="21490"   average="21490"   minValue="73701"    maxValue="73701"                               >73701</Metric>
    <Metric id="TransactionCleanupThread.RefundOldTrans"             type="timer" unit="µs" count="1" sum="184487"  average="184487"  minValue="632704"   maxValue="632704"                              >632704</Metric>
    <Metric id="Database.CreateConnection_SaveContextUserGUID"       type="timer" unit="µs" count="2" sum="7562"    average="3781"    minValue="12928"    maxValue="13006"    standardDeviation="16"     >12967</Metric>
    <Metric id="Global.CurrentUser"                                  type="timer" unit="µs" count="6" sum="4022464" average="670411"  minValue="15"       maxValue="13794345" standardDeviation="1642047">2299194</Metric>
    <Metric id="Global.CurrentUser_FetchIdentityFromDatabase"        type="timer" unit="µs" count="1" sum="4010057" average="4010057" minValue="13752614" maxValue="13752614"                            >13752614</Metric>
  </Metrics>
</Sqm>
最后,我将实际执行
SUM()
MIN()
MAX()
聚合。但现在我只想查询一个xml列

在伪代码中,我会尝试以下操作:

SELECT
    SqmId,
    Data.query('/Sqm/Metrics/Metric/@id') AS id,
    Data.query('/Sqm/Metrics/Metric/@type') AS type,
    Data.query('/Sqm/Metrics/Metric/@unit') AS unit,
    Data.query('/Sqm/Metrics/Metric/@sum') AS sum,
    Data.query('/Sqm/Metrics/Metric/@count') AS count,
    Data.query('/Sqm/Metrics/Metric/@minValue') AS minValue,
    Data.query('/Sqm/Metrics/Metric/@maxValue') AS maxValue,
    Data.query('/Sqm/Metrics/Metric/@standardDeviation') AS standardDeviation,
    Data.query('/Sqm/Metrics/Metric') AS value
FROM Sqm
但该SQL查询不起作用:

Msg 2396,第16级,状态1,第2行
XQuery[Sqm.data.query()]:属性不能出现在元素外部

我一直在寻找,令人惊讶的是,Xml查询的文档记录或示例是多么糟糕。大多数资源不是查询,而是查询变量;我没有这么做。大多数资源仅使用xml查询进行筛选和选择,而不是读取值。大多数资源读取硬编码的子节点(按索引),而不是实际值

我阅读的相关资源
更新:。值而不是。查询 我尝试随机使用
.value
,而不是
.query

SELECT
    Sqm.SqmId,
    Data.value('/Sqm/Metrics/Metric/@id', 'varchar(max)') AS id,
    Data.value('/Sqm/Metrics/Metric/@type', 'varchar(max)') AS type,
    Data.value('/Sqm/Metrics/Metric/@unit', 'varchar(max)') AS unit,
    Data.value('/Sqm/Metrics/Metric/@sum', 'varchar(max)') AS sum,
    Data.value('/Sqm/Metrics/Metric/@count', 'varchar(max)') AS count,
    Data.value('/Sqm/Metrics/Metric/@minValue', 'varchar(max)') AS minValue,
    Data.value('/Sqm/Metrics/Metric/@maxValue', 'varchar(max)') AS maxValue,
    Data.value('/Sqm/Metrics/Metric/@standardDeviation', 'varchar(max)') AS standardDeviation,
    Data.value('/Sqm/Metrics/Metric', 'varchar(max)') AS value
FROM Sqm
但这也不起作用:

Msg 2389,第16级,状态1,第3行XQuery[Sqm.data.value()]:
“value()”需要一个单例(或空序列),找到的操作数为 类型“xdt:untypedAtomic*”


实际上,您已接近目标,只需使用方法拆分行,然后获取值:

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)

使用
value
而不是
query
(必须在XQuery中指定要返回的节点索引,并将要返回的sql数据类型作为第二个参数传递):


我不明白为什么有些人建议使用
交叉应用
外部应用
将xml转换为值表。对我来说,这带来了太多的数据

下面是我的示例,演示如何创建
xml
对象,然后将其转换为表

(我在xml字符串中添加了空格,只是为了更易于阅读。)

DECLARE@str nvarchar(2000)
设置@str=''
设置@str=@str+''
设置@str=@str+''
设置@str=@str+'Mike'
SET@str=@str+'Gledhill'

SET@str=@str+'

我一直在尝试做一些非常类似的事情,但没有使用节点。但是,我的xml结构有点不同

你可以这样说:

<Metrics>
    <Metric id="TransactionCleanupThread.RefundOldTrans" type="timer" ...>
对我来说,这比使用外部应用或交叉应用更容易混淆


我希望这有助于其他人寻找更简单的解决方案

如何获取节点本身的“值”?似乎没有办法
选择m.*
来查看它构造的秘密、神奇的中间表。查询元素值的语法是什么?e、 g.
8675309
的值为“8675309”@IanBoyd抱歉,错过了,请参阅更新。如果可能存在嵌套元素,则可以使用“.”或文本来执行此查询中的别名
s
m
c
表示?@IanR.O'Brien
m
nodes()函数返回的结果集,
s
sqm
表本身,
c
是由
nodes()
function返回的结果集中数据类型为xml的列。这是一个完美的选项。该代码未命中开头的括号。在id等后面附加
/text()
,以提高性能这是最严格的方法。谢谢,工作顺利。我们如何用这种方法查询具有XML类型列的表?谢谢。好奇。。。为什么要在xml转换之前将嵌套转换为
Varbinary(max)
?谢谢。@FMFF此方法实际上与使用交叉应用的所有其他方法相同。
select
    xt.Id
    , x.m.value( '@id[1]', 'varchar(max)' ) MetricId
from
    XmlTest xt
    cross apply xt.XmlData.nodes( '/Sqm/Metrics/Metric' ) x(m)
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)
<Metrics>
    <Metric id="TransactionCleanupThread.RefundOldTrans" type="timer" ...>
<Metrics>
    <Metric>
        <id>TransactionCleanupThread.RefundOldTrans</id>
        <type>timer</type>
        .
        .
        .
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