如何从SQL Server中的表查询Xml值和属性?
我有一个包含一个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>
在这个数据的情况下,我想要:
SqmId id type unit count sum minValue maxValue standardDeviation Value ===== =================================================== ===== ==== ===== ====== ======== ======== ================= ====== 1 TransactionCleanupThread.RecordUsedTransactionShift timer µs 1 21490 73701 73701 NULL 73701 1 TransactionCleanupThread.RefundOldTrans timer µs 1 184487 632704 632704 NULL 632704 1 Database.CreateConnection_SaveContextUserGUID timer µs 2 7562 12928 13006 16 12967 1 Global.CurrentUser timer µs 6 4022464 15 13794345 1642047 2299194 1 Global.CurrentUser_FetchIdentityFromDatabase timer µs 1 4010057 13752614 13752614 NULL 13752614 2 ...
最后,我将实际执行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,Level 16,State 1,Line 2
XQuery [Sqm.data.query()]:属性可能不会出现在元素之外
我已经find了,而且Xml查询是如何logging不完善或者是exampled是多么令人吃惊。 大多数资源而不是查询表 ,查询variables ; 我没有做。 大多数资源只使用xml查询进行筛选和select,而不是读取值。 大多数资源读取硬编码子节点(按索引),而不是实际值。
我读过的相关资源
- https://stackoverflow.com/questions/966441/xml-query-in-sql-server-2008
- SQL Server查询元素值的xml属性
- SQL查询XML属性
- SQL Server 2005 XQuery和XML-DML – 第1部分
- BOL:Microsoft SQL Server 2005中的XML支持
- 在SQL Server中查询XML
- 基本的SQL Server XML查询
- BOL:query()方法(xml数据types)
- XML Workshop V – 从XML列读取值
- SQL SERVER – 发现XML数据types方法介绍 – 入门
更新:.value而不是.query
我试着随机使用.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
但是这也不起作用:
消息2389,级别16,状态1,行3 XQuery [Sqm.data.value()]:
'value()'需要一个单例(或空序列),find的types为'xdt:untypedAtomic *'的操作数
其实你接近你的目标,你只需要使用nodes()方法拆分你的行,然后得到值:
select s.SqmId, mcvalue('@id', 'varchar(max)') as id, mcvalue('@type', 'varchar(max)') as type, mcvalue('@unit', 'varchar(max)') as unit, mcvalue('@sum', 'varchar(max)') as [sum], mcvalue('@count', 'varchar(max)') as [count], mcvalue('@minValue', 'varchar(max)') as minValue, mcvalue('@maxValue', 'varchar(max)') as maxValue, mcvalue('.', 'nvarchar(max)') as Value, mcvalue('(text())[1]', 'nvarchar(max)') as Value2 from sqm as s outer apply s.data.nodes('Sqm/Metrics/Metric') as m(c)
sql小提琴演示
使用value
而不是query
(必须指定要在XQuery中返回的节点的索引以及传递sql数据types作为第二个参数返回):
select xt.Id , xmvalue( '@id[1]', 'varchar(max)' ) MetricId from XmlTest xt cross apply xt.XmlData.nodes( '/Sqm/Metrics/Metric' ) x(m)
我一直在试图做一些非常相似的事情,但不使用节点。 但是,我的XML结构有点不同。
你有这样的:
<Metrics> <Metric id="TransactionCleanupThread.RefundOldTrans" type="timer" ...>
如果它是这样的,而不是:
<Metrics> <Metric> <id>TransactionCleanupThread.RefundOldTrans</id> <type>timer</type> . . .
那么你可以简单地使用这个SQL语句。
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
对我来说,这比使用外部应用程序或交叉应用程序更容易混淆。
我希望这可以帮助别人寻找更简单的解决scheme!
我不明白为什么有些人build议使用cross apply
或outer apply
将XML转换成值的表。 对我来说,这只是带来了太多的数据。
这是我如何创build一个xml
对象,然后把它变成一个表的例子。
(我已经在我的xmlstring中添加了空格,只是为了方便阅读。)
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)
这里是输出: