从XML名称/值架构中提取值,并在结果中显示为列

时间:2013-01-11 22:18:02

标签: xml sql-server-2008 xpath xquery sql-server-2012

鉴于我在XML列中存储了这样的信息,其架构如下所示 -

<root>
  <Setting>
     <Name>BookingDate</Name>
     <Value>01 Jan 2013</Value>
  </Setting>
  <Setting>
     <Name>Price</Name>
     <Value>23.66</Value>
  </Setting>
</root>

我可以编写一个查询来提取名称&#39;作为专栏和&#39;设置&#39;作为行值,它们看起来好像我在那一行做了一个简单的选择,即

RowID | NormalColumn1 | NormalColumn2 | BookingDate  | Price
-------------------------------------------------------------
 1    |   X           |   Y           | 01 Jan 2013  | 23.66 

我可以进行静态查询但是如何编写一个在项目添加到XML时会返回更多结果的查询?我想将其放在一个带有Select *的视图中,以便人们向XML添加更多信息,更多结果将显示在视图上的查询中。

然后我可以索引这个架构,甚至可以到达键入的位置。目的是存储尚未了解的信息。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

您需要动态构建查询以获得动态数量的列,并确定哪些列需要解析XML的所有节点,如果存在大量行,则可能在服务器上很难在表中。

我建议您拥有一个包含有效设置名称的表Setting,并在触发器中将该表更新为Settings表。

要拥有反映您所拥有设置的视图,您可以在动态更新视图的表Setting上添加触发器。

SQL Fiddle

MS SQL Server 2008架构设置

create table Settings
(
  RowID int identity primary key,
  Settings xml
) 

go

create table Setting
(
  Name varchar(20) primary key
)

go

create view v_Settings as 
select RowID 
from Settings

go

create trigger tr_Settings on Settings for insert, update as
with C(Name) as
(
  select distinct T.N.value('text()[1]', 'nvarchar(20)') 
  from inserted as I
    cross apply I.Settings.nodes('/root/Setting/Name') as T(N)
)
insert into Setting(Name)
select Name
from C
where C.Name not in (select Name from Setting) 

go

create trigger tr_Setting on Setting for insert as
declare @SQL nvarchar(max)
set @SQL = 'alter view v_Settings as ' + 
           'select S.RowID'+
           (
           select ',S.Settings.value(''(root/Setting[Name="' + 
                  S.Name + 
                  '"]/Value/text())[1]'', ''varchar(max)'') as '+
                  quotename(S.Name)
           from Setting as S
           for xml path(''), type
           ).value('text()[1]', 'nvarchar(max)')+
           ' from Settings as S'

exec (@SQL)

查询1

insert into Settings values
('<root>
  <Setting>
     <Name>BookingDate</Name>
     <Value>01 Jan 2013</Value>
  </Setting>
  <Setting>
     <Name>Price</Name>
     <Value>23.66</Value>
  </Setting>
</root>')

select *
from v_Settings

<强> Results

| ROWID | BOOKINGDATE | PRICE |
-------------------------------
|     5 | 01 Jan 2013 | 23.66 |

查询2

insert into Settings values
('<root>
  <Setting>
     <Name>BookingDate</Name>
     <Value>02 Jan 2013</Value>
  </Setting>
  <Setting>
     <Name>PriceX</Name>
     <Value>24.66</Value>
  </Setting>
</root>')

select *
from v_Settings

<强> Results

| ROWID | BOOKINGDATE |  PRICE | PRICEX |
-----------------------------------------
|     5 | 01 Jan 2013 |  23.66 | (null) |
|     6 | 02 Jan 2013 | (null) |  24.66 |

<强>更新

从上面的评论看来,您已经有了一个跟踪所有可能的设置名称的表。如果是这种情况,您不需要Settings上的触发器。 如果您确保在更新表Setting后重建视图,则实际上您不需要Setting上的触发器。

相关问题