XMLを階層SQLテーブルに変換する方法を学習しようとしています。
Microsoftフォーラムから古いコードスニペットを見つけましたが、これは基本的に私がやろうとしていることですが、特にxmlがロードされた後、誰かがこのコードの行ごとに何が起こっているのかを理解するのに役立つかどうか疑問に思っていました@XML
--I understand this part, just making the tables
DECLARE @Books TABLE (BookID int identity(1,1),BookTitle varchar(50),BookLanguage varchar(20),BookPrice decimal(18,2))
DECLARE @Topics TABLE (TopicID int identity(1,1),BookID int,TopicTitile varchar(50),Page int)
--I understand this part, defining the @xml variable to be the xml below.. just a usual xml...
DECLARE @xml XML
SET @xml = '
<bookstore>
<name>My Bookstore</name><br/>
<location>New York</location><br/>
<book>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
<tableOfContents>
<topic>
<title>Harry Potter Topic 1</title>
<page>2</page>
</topic>
<topic>
<title>Harry Potter Topic 2</title>
<page>5</page>
</topic>
</tableOfContents>
</book>
<book>
<title lang="eng">Learning XML</title>
<price>39.95</price>
<tableOfContents>
<topic>
<title>Learning XML Topic 1</title>
<page>1</page>
</topic>
<topic>
<title>Learning XML Topic 2</title>
<page>2</page>
</topic>
</tableOfContents>
</book>
</bookstore>'
--what is going on below here? I am familiar with inserting data into tables,
--but what kind of insert is this where you are selecting some things and then doing a
--from @xml.nodes also, what is that T(c) at the end? and do we always have to put
--a [1] after each xml element to denote we are referring to the first one we encounter?
INSERT INTO @Books
SELECT T.c.value('title[1]','varchar(50)') AS 'BookTitle',
T.c.value('(title/@lang)[1]','varchar(20)') AS 'BookLanguage',
T.c.value('price[1]','decimal(18,2)') AS 'BookPrice'
FROM @xml.nodes('/bookstore/book') T(c)
--what is going on here as well? what is n(x) ?
--could you explain this line by line-ish as well? I ran this on
--SQL Server Management Studio and noticed that both of the 'topic titles' for each
--book got inserted. Where in the code did those get put into the table?
INSERT INTO @Topics
SELECT b.BookID,n.x.value('title[1]','varchar(50)') AS 'TopicTitile',
n.x.value('page[1]','int') AS 'TopicPage'
FROM @Books b
cross apply @xml.nodes('/bookstore/book/tableOfContents/topic[../../title=sql:column("b.BookTitle")]') n(x)
--below here is just regular sql selects so this makes sense.
SELECT BookID,BookTitle,BookLanguage,BookPrice FROM @Books
SELECT TopicID,BookID,TopicTitile,Page FROM @Topics
私が参照していて、古い投稿から学ぼうとしたフォーラムは次のとおりです。
http://social.msdn.Microsoft.com/Forums/en/sqlxml/thread/7216ccc9-c1d7-418d-95a2-ec3a96de2c27
BOLさんのコメント:
構文:
nodes (XQuery) as Table(Column)
これは簡単な例です:
DECLARE @x xml ;
SET @x='<Root>
<row id="1"><name>Larry</name><oflw>some text</oflw></row>
<row id="2"><name>moe</name></row>
<row id="3" />
</Root>';
SELECT T.c.query('.') AS result
FROM @x.nodes('/Root/row') T(c);
GO
Xmlデータ型をリレーショナルデータに「変換」または細断することは特別な通知です。 xmlパーツをテーブルの列にマップするだけです。 T-テーブル、c-列、nodes()-メソッド
value (XQuery, SQLType)
したがって、T.c.value( 'title [1]'、 'varchar(50)')は要素のタイトルの値を読み取り、それをvarchar(50)データ型に変換します。 [1]はvalue()メソッドのパス式の最後に追加され、パス式がシングルトンを返すことを明示的に示します(混乱するだけです。XPathのグループの最初の要素を意味します)。
したがって、T.c.value( '(title/@ lang)[1]'、 'varchar(20)')は、要素タイトルの属性langの値を読み取り、それをvarchar(20)データ型に変換します。
そして、@ xml.nodes( '/ bookstore/book')はxmlの読み取りを開始するポイントにあります。この場合、このxmlからすべてのブック要素(ノード)を返します。
このクエリには2つのエイリアスT1(Locations)とT2(steps)があります
[〜#〜]追加[〜#〜]
SELECT
ProductModelID
, Locations.value('./@LocationID','int') as LocID
, steps.query('.') as Step
FROM Production.ProductModel
CROSS APPLY Instructions.nodes('
declare namespace MI="http://schemas.Microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
/MI:root/MI:Location')
as T1(Locations)
CROSS APPLY T1.Locations.nodes('
declare namespace MI="http://schemas.Microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
./MI:step ')
as T2(steps)
GO