Tengo una tabla que contiene una Xml
columna:
SELECT *
FROM Sqm
Una muestra de los xml
datos de una fila sería:
<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>
En el caso de estos datos, querría:
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 ...
Al final he hecho estarán realizando SUM()
, MIN()
, MAX()
agregación. Pero por ahora solo intento consultar una columna xml.
En pseudocódigo, probaría algo como:
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
Pero esa consulta SQL no funciona:
Msg 2396, nivel 16, estado 1, línea 2
XQuery [Sqm.data.query ()]: el atributo no puede aparecer fuera de un elemento
He cazado, y es sorprendente lo mal documentado o ilustrado que está la consulta XML. La mayoría de los recursos, en lugar de consultar una tabla , consulta una variable ; que no estoy haciendo. La mayoría de los recursos solo usan consultas xml para filtrar y seleccionar, en lugar de leer valores. La mayoría de los recursos leen nodos secundarios codificados (por índice), en lugar de valores reales.
Recursos relacionados que leí
- /programming/966441/xml-query-in-sql-server-2008
- Atributo xml de consulta de SQL Server para un valor de elemento
- Atributos XML de consultas SQL
- SQL Server 2005 XQuery y XML-DML - Parte 1
- BOL: Soporte XML en Microsoft SQL Server 2005
- Consultar XML en SQL Server
- Consultas XML básicas de SQL Server
- BOL: método query () (tipo de datos xml)
- Taller XML V: lectura de valores de columnas XML
- SQL SERVER - Introducción al descubrimiento de métodos de tipos de datos XML - Introducción
Actualización: .value en lugar de .query
Intenté usar aleatoriamente .value
, en lugar de .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
Pero eso tampoco funciona:
Msg 2389, nivel 16, estado 1, línea 3 XQuery [Sqm.data.value ()]:
'value ()' requiere un singleton (o secuencia vacía), operando encontrado de tipo 'xdt: untypedAtomic *'
select m.*
ver la mesa secreta, mágica e intermedia que construyó. ¿Cuál es la sintaxis para consultar el valor de un elemento? por ejemplo, el valor de<Metric>8675309</Metric>
es "8675309"s
,m
yc
en esta consulta?m
es el conjunto de resultados devuelto por lanodes()
función,s
es lasqm
tabla en sí,c
es una columna con el tipo de datos xml en el conjunto de resultados devuelto por lanodes()
funciónHe estado tratando de hacer algo muy similar pero sin usar los nodos. Sin embargo, mi estructura xml es un poco diferente.
Lo tienes así:
<Metrics> <Metric id="TransactionCleanupThread.RefundOldTrans" type="timer" ...>
Si fuera así en su lugar:
<Metrics> <Metric> <id>TransactionCleanupThread.RefundOldTrans</id> <type>timer</type> . . .
Entonces podría simplemente usar esta declaración 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
Para mí, esto es mucho menos confuso que usar la aplicación externa o la aplicación cruzada.
¡Espero que esto ayude a alguien más a buscar una solución más simple!
fuente
/text()
después de la identificación, etc. para aumentar el rendimientouse en
value
lugar dequery
(debe especificar el índice del nodo para devolver en XQuery, así como pasar el tipo de datos sql para devolver como segundo parámetro):select xt.Id , x.m.value( '@id[1]', 'varchar(max)' ) MetricId from XmlTest xt cross apply xt.XmlData.nodes( '/Sqm/Metrics/Metric' ) x(m)
fuente
No entiendo por qué algunas personas sugieren usar
cross apply
oouter apply
convertir el xml en una tabla de valores. Para mí, eso trajo demasiados datos.Aquí está mi ejemplo de cómo crearía un
xml
objeto y luego lo convertiría en una tabla.(He agregado espacios en mi cadena xml, solo para que sea más fácil de leer).
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)
Y aquí está el resultado:
fuente
Varbinary(max)
antes del elenco xml, por favor?