J'ai une table qui contient une Xml
colonne:
SELECT *
FROM Sqm
Un échantillon des xml
données d'une ligne serait:
<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>
Dans le cas de ces données, je voudrais:
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 ...
En fin de compte, je vais effectivement assurer SUM()
, MIN()
, l' MAX()
agrégation. Mais pour l'instant, j'essaie simplement d' interroger une colonne xml.
En pseudo-code, j'essaierais quelque chose comme:
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
Mais cette requête SQL ne fonctionne pas:
Msg 2396, niveau 16, état 1, ligne 2
XQuery [Sqm.data.query ()]: l'attribut peut ne pas apparaître en dehors d'un élément
J'ai chassé, et c'est incroyable à quel point les requêtes Xml sont mal documentées ou examinées. La plupart des ressources plutôt que d'interroger une table , interrogez une variable ; ce que je ne fais pas. La plupart des ressources n'utilisent que des requêtes XML pour le filtrage et la sélection, plutôt que pour la lecture des valeurs. La plupart des ressources lisent les nœuds enfants codés en dur (par index), plutôt que les valeurs réelles.
Ressources connexes que j'ai lues
- /programming/966441/xml-query-in-sql-server-2008
- Attribut XML de requête SQL Server pour une valeur d'élément
- SQL interrogeant des attributs XML
- SQL Server 2005 XQuery et XML-DML - Partie 1
- BOL: prise en charge XML dans Microsoft SQL Server 2005
- Requête XML dans SQL Server
- Requête XML de base SQL Server
- BOL: query (), méthode (type de données xml)
- Atelier XML V - Lecture de valeurs à partir de colonnes XML
- SQL SERVER - Introduction à la découverte des méthodes de type de données XML - Introduction
Mise à jour: .value plutôt que .query
J'ai essayé d'utiliser au hasard .value
, à la place 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
Mais cela ne fonctionne pas non plus:
Msg 2389, niveau 16, état 1, ligne 3 XQuery [Sqm.data.value ()]:
'value ()' nécessite un singleton (ou séquence vide), opérande trouvé de type 'xdt: untypedAtomic *'
select m.*
voir la table intermédiaire secrète, magique, qu'il a construite. Quelle est la syntaxe pour interroger la valeur d'un élément? Par exemple, la valeur de<Metric>8675309</Metric>
est "8675309"s
,m
etc
dans cette requête?m
est l'ensemble de résultats retourné par lanodes()
fonction,s
est lasqm
table elle-même,c
est la colonne avec le type de données xml dans l'ensemble de résultats retourné par lanodes()
fonctionJ'ai essayé de faire quelque chose de très similaire mais sans utiliser les nœuds. Cependant, ma structure xml est un peu différente.
Vous l'avez comme ça:
<Metrics> <Metric id="TransactionCleanupThread.RefundOldTrans" type="timer" ...>
Si c'était comme ça à la place:
<Metrics> <Metric> <id>TransactionCleanupThread.RefundOldTrans</id> <type>timer</type> . . .
Ensuite, vous pouvez simplement utiliser cette instruction 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
Pour moi, c'est beaucoup moins déroutant que d'utiliser l'application externe ou l'application croisée.
J'espère que cela aidera quelqu'un d'autre à la recherche d'une solution plus simple!
la source
/text()
après id, etc. pour augmenter les performancesutiliser à la
value
place dequery
(doit spécifier l'index du nœud à renvoyer dans XQuery ainsi que passer le type de données sql à renvoyer comme deuxième paramètre):select xt.Id , x.m.value( '@id[1]', 'varchar(max)' ) MetricId from XmlTest xt cross apply xt.XmlData.nodes( '/Sqm/Metrics/Metric' ) x(m)
la source
Je ne comprends pas pourquoi certaines personnes suggèrent d'utiliser
cross apply
ououter apply
de convertir le XML en une table de valeurs. Pour moi, cela a simplement rapporté beaucoup trop de données.Voici mon exemple de la façon dont vous créez un
xml
objet, puis le transformez en table.(J'ai ajouté des espaces dans ma chaîne xml, juste pour la rendre plus facile à lire.)
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)
Et voici la sortie:
la source
Varbinary(max)
avant la distribution XML s'il vous plaît?