sql-server - 抽出 - xml sql文




SQL ServerでテーブルからXml値と属性をクエリする方法 (3)

私は、 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クエリは動作しません:

メッセージ2396、レベル16、状態1、行2
XQuery [Sqm.data.query()]:属性が要素の外部に表示されないことがある

私は狩りをしてきました.Xmlのクエリがいかに不十分に文書化されていたのか、それともどのように証明されたのかは驚くべきことです。 ほとんどのリソースではなく、 テーブルのクエリ、 変数のクエリ、 私はやっていない。 ほとんどのリソースは、値を読み取るのではなく、フィルタリングと選択のためにxmlクエリを使用します。 ほとんどのリソースは、実際の値ではなく、ハードコードされた子ノードを(索引によって)読み込みます。

読んでいる関連リソース

更新:.queryではなく.value

.query代わりにランダムに.queryを使ってみ.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()'はシングルトン(または空のシーケンス)を必要とし、 'xdt:untypedAtomic *'型のオペランドが見つかりました


query代わりにvalueを使用しquery (XQueryで返すノードのインデックスを指定し、SQLデータ型を渡して2番目のパラメータとして返す必要があります)。

select
    xt.Id
    , x.m.value( '@id[1]', 'varchar(max)' ) MetricId
from
    XmlTest xt
    cross apply xt.XmlData.nodes( '/Sqm/Metrics/Metric' ) x(m)

いくつかの人々がxmlを値の表に変換outer applyためにcross applyまたはouter applyを使用することを提案している理由はわかりません。 私にとっては、あまりにも多くのデータを取り戻しただけです。

ここでは、 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)

そしてここに出力があります:


私は非常に似たようなことをしようとしていますが、ノードを使用していません。 しかし、私の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

私には、外側の適用またはクロス適用を使用するよりもずっと混乱が少なくなります。

私はこれが他の誰かが簡単な解決策を探しているのに役立つことを願っています





sqlxml