Mam tabelę zawierającą Xml
kolumnę:
SELECT *
FROM Sqm
Przykładem xml
danych w wierszu byłoby:
<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>
W przypadku tych danych chciałbym:
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 ...
W końcu będę faktycznie wystąpi SUM()
, MIN()
, MAX()
agregacji. Ale na razie próbuję tylko zapytać kolumnę xml.
W pseudokodzie chciałbym spróbować czegoś takiego:
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
Ale to zapytanie SQL nie działa:
Msg 2396, poziom 16, stan 1, wiersz 2
XQuery [Sqm.data.query ()]: atrybut nie może pojawiać się poza elementem
Polowałem i to niesamowite, jak słabo udokumentowane, lub na przykład, zapytania Xml są. Większość zasobów zamiast odpytywania tabeli , odpytuje zmienną ; czego nie robię. Większość zasobów używa zapytań XML tylko do filtrowania i zaznaczania, zamiast odczytywać wartości. Większość zasobów odczytuje zakodowane na stałe węzły potomne (według indeksu), a nie rzeczywiste wartości.
Powiązane zasoby, które przeczytałem
- /programming/966441/xml-query-in-sql-server-2008
- Atrybut XML zapytania SQL Server dla wartości elementu
- Zapytania SQL dotyczące atrybutów XML
- SQL Server 2005 XQuery i XML-DML - część 1
- BOL: Obsługa XML w Microsoft SQL Server 2005
- Zapytania XML w SQL Server
- Podstawowe zapytania XML programu SQL Server
- BOL: query (), metoda (typ danych xml)
- XML Workshop V - Odczytywanie wartości z kolumn XML
- SERWER SQL - Wprowadzenie do odkrywania metod typu danych XML - elementarz
Aktualizacja: .value zamiast .query
Próbowałem losowo użyć .value
zamiast .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
Ale to też nie działa:
Msg 2389, poziom 16, stan 1, wiersz 3 XQuery [Sqm.data.value ()]:
„value ()” wymaga singletona (lub pustej sekwencji), znaleziono operand typu „xdt: untypedAtomic *”
select m.*
zobaczyć sekretny, magiczny, pośredni stół, który skonstruował. Jaka jest składnia zapytania o wartość elementu? np. wartość<Metric>8675309</Metric>
to „8675309”s
,m
ic
reprezentują w tej kwerendzie?m
jest resultset zwracany przeznodes()
funkcję,s
tosqm
sam stół,c
jest kolumna z typem danych XML w zestawie wyników zwracanych przeznodes()
funkcjęPróbowałem zrobić coś bardzo podobnego, ale nie korzystałem z węzłów. Jednak moja struktura xml jest trochę inna.
Masz to tak:
<Metrics> <Metric id="TransactionCleanupThread.RefundOldTrans" type="timer" ...>
Gdyby zamiast tego wyglądało tak:
<Metrics> <Metric> <id>TransactionCleanupThread.RefundOldTrans</id> <type>timer</type> . . .
Następnie możesz po prostu użyć tej instrukcji 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
Dla mnie jest to znacznie mniej zagmatwane niż stosowanie aplikacji zewnętrznej lub nakładania krzyżowego.
Mam nadzieję, że pomoże to komuś innemu szukającemu prostszego rozwiązania!
źródło
/text()
po id itp., aby zwiększyć wydajnośćużyj
value
zamiastquery
(należy określić indeks węzła do zwrócenia w XQuery, a także przekazać typ danych sql do zwrócenia jako drugi parametr):select xt.Id , x.m.value( '@id[1]', 'varchar(max)' ) MetricId from XmlTest xt cross apply xt.XmlData.nodes( '/Sqm/Metrics/Metric' ) x(m)
źródło
Nie rozumiem, dlaczego niektórzy sugerują użycie
cross apply
lubouter apply
przekonwertowanie XML na tabelę wartości. Dla mnie to po prostu przyniosło zbyt wiele danych.Oto mój przykład, w jaki sposób można utworzyć
xml
obiekt, a następnie przekształcić go w tabelę.(Dodałem spacje do mojego ciągu xml, aby ułatwić czytanie).
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)
A oto wynik:
źródło
Varbinary(max)
przed rzutowaniem XML, proszę?