从sql列中的xml中提取值和属性

时间:2016-05-04 20:31:19

标签: sql-server xml

我正在处理包含多种数据类型的Microsoft SQL Server表,包括xml列。例如:

CREATE TABLE [sites]
(
    [site_id] [int] NOT NULL,
    [organization_id] [int] NULL,
    [site_creationDate] [datetime] NULL,
    [site_active] [bit] NULL,
    [site_activatedBy] [varchar](20) NULL,
    [contentModel_id] [int] NULL,
    [site_settings] [xml] NULL
);

以下是[site_settings]列中XML的含义:

示例1:

<settings>
  <s key="hasinventorynotifier" value="0" type="BIT" />
  <s key="displayinstocknotifier" value="1" type="BIT" />
  <s key="usesimplequoteform" type="BIT" value="1" />
</settings>

示例2:

<settings>
  <s key="isvisionimpaired" type="Bit" value="0" />
  <s key="insurancerequesturl" type="String" value="" />
  <s key="haswheelstudio" type="Bit" value="0" />
  <s key="hasironfunnel" type="Bit" value="0" />
  <s key="haselasticsearch" type="Bit" value="0" />
  <s key="hasinventorynotifier" type="Bit" value="0" />
  <s key="themeconfigurationjson" type="String" value="{&amp;quot;siteHeader&amp;quot;:{&amp;quot;scheme&amp;quot;:&amp;quot;light&amp;quot;,&amp;quot;headerLinks&amp;quot;:false,&amp;quot;navType&amp;quot;:&amp;quot;expanded&amp;quot;},&amp;quot;body&amp;quot;:{&amp;quot;grid&amp;quot;:&amp;quot;compact&amp;quot;},&amp;quot;siteFooter&amp;quot;:{&amp;quot;scheme&amp;quot;:&amp;quot;light&amp;quot;},&amp;quot;logo&amp;quot;:{&amp;quot;enabled&amp;quot;:true,&amp;quot;imageUrl&amp;quot;:&amp;quot;//cdnmedia.example.com/images/organizations/7a1fd181-1154-4cb6-8c43-a6f354b9f824/logo/dealer-logo.gif?v=1455044570132&amp;quot;}}" />
  <s key="hasautoquote" type="Bit" value="0" />
  <s key="usesimplequoteform" type="Bit" value="1" />
  <s key="overrideinventorysearchtitle" type="Bit" value="1" />
  <s key="overrideshowcasetitle" type="Bit" value="1" />
  <s key="financingexternalurl" type="String" value="" />
  <s key="disablemakeofferrequest" type="Bit" value="0" />
  <s key="enablereceiveoffers" type="Bit" value="1" />
  <s key="vehiclehistoryurl" type="String" value="" />
  <s key="displayinstocknotifier" type="Bit" value="1" />
  <s key="disableautoresponseemail" type="Bit" value="0" />
  <s key="enablesolditemsremoval" type="Bit" value="0" />
  <s key="usefinancingexternalurl" type="Bit" value="0" />
</settings>

从上面的示例中可以看出,xml列在行与行之间不是很一致,并且不显示所有&#34;键&#34;。 (注意,我没有设计这个数据库。)

我想创建一个显示所有列的视图,还要从[site_settings]列的xml结构中提取一些值,并在我的视图中将它们显示为新列。我认为我们的xml有点时髦,因为我尝试这样做的所有例子都没有找到我。

这就是我想要的东西:

CREATE VIEW [vw_Sites]
AS 
    SELECT 
        [site_id], [organization_id],
        [site_creationDate], [site_active], [site_activatedBy],
        [contentModel_id], [hasinventorynotifier],
        [displayinstocknotifier], [usesimplequoteform],
        [isvisionimpaired]  (and more xml keys, etc...)
    FROM 
        [sites] WITH (NOLOCK)
GO

我已尝试通过在下面的这些查询中选择列的值来提取一些提取方法,但结果会返回NULL或空白。

SELECT 
    [site_settings].value('usesimplequoteform[1]','bit') AS Test1,
    [site_settings].value('settings[1]','varchar(10)') AS Test2,
    [site_settings].value('(s[@key="usesimplequoteform"]/@value)[1]','int') AS Test3
FROM
    [sites]

或者,一位矿业同事建议使用以下案例陈述,这些陈述确实有效,但我想知道是否有更好的方法。案例如下:

SELECT 
    CASE WHEN CHARINDEX('usesimplequoteform" type="Bit" value="1"',CONVERT(VARCHAR(MAX),site_settings),1) > 0 THEN 1 
            WHEN CHARINDEX('usesimplequoteform" value="1" type="Bit"',CONVERT(VARCHAR(MAX),site_settings),1) > 0 THEN 1
            ELSE 0 
       END AS useSimpleQuoteForm
FROM [sites]

但是有没有人有更好的方法?上面的例子只适用于位变量,其中一些是string(varchar)类型。任何帮助将不胜感激!

澄清输出

基本上,输出将是一个视图,其中包含表[sites]中的所有当前列以及[sites]。[site_settings]列中可能存在的每个键的其他列。

[site_id]   [organization_id]   [site_creationDate] [site_active]   [site_activatedBy]  [contentModel_id]   [hasinventorynotifier]  [displayinstocknotifier]    [usesimplequoteform]    [the keys etc in xml]
5036            4886            2016-01-04 10:16:01.860     1           system              8                       1                           0                           1               (value)
5037            2386            2015-01-05 11:29:23.880     1           system              2                       0                           0                           1               (value)

1 个答案:

答案 0 :(得分:1)

这是一种将所有值 输出的方法:

您的XML减少了:

DECLARE @xml XML=
'<settings>
  <s key="isvisionimpaired" type="Bit" value="0" />
  <s key="insurancerequesturl" type="String" value="" />
  <s key="haswheelstudio" type="Bit" value="0" />
</settings>'

SELECT a.b.value('@key','varchar(max)') AS s_key
      ,a.b.value('@type','varchar(max)') AS s_type
      ,a.b.value('@value','varchar(max)') AS s_value
FROM @xml.nodes('settings/s') AS a(b);

另一种方法可能是 - 如果你知道所有可能的数据 - 一个接一个地写下所有数据:

SELECT @xml.value('(/settings/s[@key="isvisionimpaired"]/@value)[1]','bit') AS isvisionimpaired
      ,@xml.value('(/settings/s[@key="insurancerequesturl"]/@value)[1]','varchar(max)') AS insurancerequesturl
      ,@xml.value('(/settings/s[@key="haswheelstudio"]/@value)[1]','bit') AS haswheelstudio
      --all possible data here

在这种情况下,缺失的值只会返回空...

优势:您可以指定正确的数据类型并使用“发言”列名称(在您的情况下可能是密钥的名称)。

第三种方法可能是动态SQL,您可以使用 中的所有信息生成语句,以生成与上面完全相同的语句。这样做可以动态指定列名和数据类型。

最后,您需要一个EXEC,这使得无法将此方法集成到诸如VIEW之类的即席查询中。

编辑:这应该是你需要的:

根据你的评论

SELECT *
      ,[site_settings].value('(/settings/s[@key="isvisionimpaired"]/@value)[1]','bit') AS isvisionimpaired
      ,[site_settings].value('(/settings/s[@key="insurancerequesturl"]/@value)[1]','varchar(max)') AS insurancerequesturl
      ,[site_settings].value('(/settings/s[@key="haswheelstudio"]/@value)[1]','bit') AS haswheelstudio
      --all possible data here
FROM [sites]