Ian*_*oyd 76 xml sql-server sql-server-2005 sqlxml sql-server-2008-r2
我有一个包含Xml列的表:
SELECT *
FROM Sqm
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)
对于这些数据,我希望:
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 ...
Run Code Online (Sandbox Code Playgroud)
最后,我需要实际执行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
Run Code Online (Sandbox Code Playgroud)
但该SQL查询不起作用:
消息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
Run Code Online (Sandbox Code Playgroud)
但这也行不通:
消息2389,级别16,状态1,行3 XQuery [Sqm.data.value()]:
'value()'需要单例(或空序列),找到类型为'xdt:untypedAtomic*'的操作数
Rom*_*kar 101
实际上你接近你的目标,你只需要使用nodes()方法来分割你的行,然后获取值:
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)
Run Code Online (Sandbox Code Playgroud)
使用value而不是query(必须指定要在XQuery中返回的节点索引以及将sql数据类型作为第二个参数返回):
select
xt.Id
, x.m.value( '@id[1]', 'varchar(max)' ) MetricId
from
XmlTest xt
cross apply xt.XmlData.nodes( '/Sqm/Metrics/Metric' ) x(m)
Run Code Online (Sandbox Code Playgroud)
我不明白为什么有些人建议使用cross apply或outer apply将xml转换为值表.对我来说,这只会带来太多的数据.
这是我如何创建xml对象,然后将其转换为表格的示例.
(我在我的xml字符串中添加了空格,只是为了更容易阅读.)
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)
Run Code Online (Sandbox Code Playgroud)
这是输出:
小智 7
我一直在尝试做一些非常相似但没有使用节点的东西.但是,我的xml结构有点不同.
你有这样的:
<Metrics>
<Metric id="TransactionCleanupThread.RefundOldTrans" type="timer" ...>
Run Code Online (Sandbox Code Playgroud)
如果是这样的话:
<Metrics>
<Metric>
<id>TransactionCleanupThread.RefundOldTrans</id>
<type>timer</type>
.
.
.
Run Code Online (Sandbox Code Playgroud)
然后你可以简单地使用这个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
Run Code Online (Sandbox Code Playgroud)
对我来说,这比使用外部申请或交叉申请要困难得多.
我希望这可以帮助其他人寻找更简单的解决方案!
| 归档时间: |
|
| 查看次数: |
211651 次 |
| 最近记录: |