草庐IT

xml - TSQL FOR XML 路径属性,类型

coder 2024-06-24 原文

基本上我需要从数据库中输出单值和多值字段。大多数数据用户都不是技术人员,如果他们能够阅读 XML 并理解它,那就太好了。在另一篇文章的帮助下,我几乎一路走到了那里。

我遇到的问题是元素名称不能有任何空格。需要包含可能包含空格的显示名称。例如 MVtext displayName="多值文本"。如果正确答案是内联模式或其他方法,请告诉我。这不像我可以发布静态模式,因为应用程序可以动态添加字段。并且字段可以随着报告的类型而改变。这些字段在一个表中,我读取该表以构建选择。

如何传达可能包含元素空格的显示名称? SQL 2008 R2。

   SELECT top 4
     [sv].[sID] AS '@sID'
    ,[sv].[sParID] AS '@sParID' 
    ,[sv].[docID] AS 'docID'
    ,[sv].addDate as 'addDate'
    ,(SELECT [value] AS 'value'
       FROM  [docMVtext] as [mv]
       WHERE [mv].[sID] = [sv].[sID]
         AND [mv].[fieldID] = '113'
       ORDER BY [mv].[value]
       FOR XML PATH (''), type
     ) AS "To"  
    ,(SELECT [value] AS 'value'
       FROM  [docMVtext] as [mv]
       WHERE [mv].[sID] = [sv].[sID]
         AND [mv].[fieldID] = '130'
       ORDER BY [mv].[value]
       FOR XML PATH (''), type
     ) AS "MVtest" 
  FROM  [docSVsys] as [sv]
  WHERE [sv].[sID] >= '57' 
  ORDER BY 
      [sv].[sParID], [sv].[sID]
  FOR XML PATH('Document'), root('Documents')

产生:

<Documents>
  <Document sID="57" sParID="57">
    <docID>3.818919.C41P3UKK00BRICLAY0AR1ET2EBPYSU4SA</docID>
    <addDate>2011-10-28T12:26:00</addDate>
    <To>
      <value>Frank Ermis</value>
      <value>Keith Holst</value>
      <value>Mike Grigsby</value>
    </To>
    <MVtest>
      <value>MV test 01</value>
      <value>MV test 02</value>
      <value>MV test 03</value>
      <value>MV test 04</value>
    </MVtest>
  </Document>
  <Document sID="58" sParID="57">
    <docID>3.818919.C41P3UKK00BRICLAY0AR1ET2EBPYSU4SA.1</docID>
    <addDate>2011-10-28T12:26:00</addDate>
  </Document>
  <Document sID="59" sParID="59">
    <docID>3.818920.KJKP5LYKTNIODOEI4JDOKJ2BXJI5P0BIA</docID>
    <addDate>2011-10-28T12:26:00</addDate>
    <To>
      <value>Vladimir Gorny</value>
    </To>
  </Document>
  <Document sID="60" sParID="59">
    <docID>3.818920.KJKP5LYKTNIODOEI4JDOKJ2BXJI5P0BIA.1</docID>
    <addDate>2011-10-28T12:26:00</addDate>
  </Document>
</Documents>

我累了

  SELECT  [value] AS 'value', 'MV test' as 'dispName'

但是我明白了

 <MVtest>
  <value>MV test 01</value>
  <dispName>MV test</dispName>
  <value>MV test 02</value>
  <dispName>MV test</dispName>
  <value>MV test 03</value>
  <dispName>MV test</dispName>
  <value>MV test 04</value>
  <dispName>MV test</dispName>
</MVtest>

SELECT [value] AS 'value', 'MV test' as '@dispName' 抛出执行错误 行标记省略(空行标记名称)不能用于以属性为中心的 FOR XML 序列化

期望的输出:

  <Documents>
  <Document sID="57" sParID="57">
    <docID>3.818919.C41P3UKK00BRICLAY0AR1ET2EBPYSU4SA</docID>
    <addDate>2011-10-28T12:26:00</addDate>
    <To>
      <value>Frank Ermis</value>
      <value>Keith Holst</value>
      <value>Mike Grigsby</value>
    </To>
    <MVtest dispName="Multi Value Text">
      <value>MV test 01</value>
      <value>MV test 02</value>
      <value>MV test 03</value>
      <value>MV test 04</value>
    </MVtest>
  </Document>
  </Documents>

解决方案:

SELECT top 4
     [sv].[sID] AS '@sID'
    ,[sv].[sParID] AS '@sParID'
    ,'SV' as 'docID/@SVMV' 
    ,[sv].[docID] AS 'docID'
    ,'SV' as 'addDate/@SVMV'
    ,[sv].addDate as 'addDate'
    ,'Email To' as 'To/@DisplayName'
    ,'MV' as 'To/@SVMV'
    ,(SELECT [value] AS 'value'
       FROM  [docMVtext] as [mv]
       WHERE [mv].[sID] = [sv].[sID]
         AND [mv].[fieldID] = '113'
       ORDER BY [mv].[value]
       FOR XML PATH (''), type
     ) AS "To"
    ,'Multi Value Text Sample' as 'MVtext130/@DisplayName'
    ,'MV' as 'MVtext130/@SVMV'      
    ,(SELECT  [value] AS 'value' 
       FROM  [docMVtext] as [mv]
       WHERE [mv].[sID] = [sv].[sID]
         AND [mv].[fieldID] = '130'
       ORDER BY [mv].[value]
       FOR XML PATH (''), type
     ) AS "MVtext130" 
  FROM  [docSVsys] as [sv]
  WHERE [sv].[sID] >= '57' 
  ORDER BY [sv].[sParID], [sv].[sID]
  FOR XML PATH('Document'), root('Documents') 

解决方案输出:

<Documents>
  <Document sID="57" sParID="57">
    <docID SVMV="SV">3.818919.C41P3UKK00BRICLAY0AR1ET2EBPYSU4SA</docID>
    <addDate SVMV="SV">2011-10-28T12:26:00</addDate>
    <To DisplayName="Email To" SVMV="MV">
      <value>Frank Ermis</value>
      <value>Keith Holst</value>
      <value>Mike Grigsby</value>
    </To>
    <MVtext130 DisplayName="Multi Value Text Sample" SVMV="MV">
      <value>MV test 01</value>
      <value>MV test 02</value>
      <value>MV test 03</value>
      <value>MV test 04</value>
    </MVtext130>
  </Document>
  <Document sID="58" sParID="57">
    <docID SVMV="SV">3.818919.C41P3UKK00BRICLAY0AR1ET2EBPYSU4SA.1</docID>
    <addDate SVMV="SV">2011-10-28T12:26:00</addDate>
    <To DisplayName="Email To" SVMV="MV" />
    <MVtext130 DisplayName="Multi Value Text Sample" SVMV="MV" />
  </Document>
  <Document sID="59" sParID="59">
    <docID SVMV="SV">3.818920.KJKP5LYKTNIODOEI4JDOKJ2BXJI5P0BIA</docID>
    <addDate SVMV="SV">2011-10-28T12:26:00</addDate>
    <To DisplayName="Email To" SVMV="MV">
      <value>Vladimir Gorny</value>
    </To>
    <MVtext130 DisplayName="Multi Value Text Sample" SVMV="MV" />
  </Document>
  <Document sID="60" sParID="59">
    <docID SVMV="SV">3.818920.KJKP5LYKTNIODOEI4JDOKJ2BXJI5P0BIA.1</docID>
    <addDate SVMV="SV">2011-10-28T12:26:00</addDate>
    <To DisplayName="Email To" SVMV="MV" />
    <MVtext130 DisplayName="Multi Value Text Sample" SVMV="MV" />
  </Document>
</Documents>

这是对我提出的问题的一个很好的解决方案。添加属性的一个症状是,即使存在零值行,我也会得到元素。理想情况下,如果没有值,它不会列出元素。

尝试了 Case 语句,但即使我将值设置为 '',它也会显示该元素。

    ,[MVtext130/@DisplayName] = 
     Case (select COUNT(*) FROM [docMVtext] 
                  WHERE [docMVtext].[sID] = [sv].[sID]
                  AND [docMVtext].[fieldID] = '130')
       when '0' then ''
       else 'Multi Value Text Sample'
     end 

不列出没有值的元素的更新解决方案:

    SELECT top 4
     [sv].[sID] AS '@sID'
    ,[sv].[sParID] AS '@sParID'
    ,'SV' as 'docID/@SVMV' 
    ,[sv].[docID] AS 'docID'
    ,'SV' as 'addDate/@SVMV'
    ,[sv].addDate as 'addDate'
    ,(select top(1) 'Email To'
      from [docMVtext] as C
      where C.[sID] = [sv].[sID] and c.fieldID = '113' ) as 'To/@DisplayName'
    ,(select top(1) 'MV'
      from [docMVtext] as C
      where C.[sID] = [sv].[sID] and c.fieldID = '113' ) as 'To/@SVMV'
    --,'Email To' as 'To/@DisplayName'
    --,'MV' as 'To/@SVMV'
    ,(SELECT [value] AS 'value'
       FROM  [docMVtext] as [mv]
       WHERE [mv].[sID] = [sv].[sID]
         AND [mv].[fieldID] = '113'
       ORDER BY [mv].[value]
       FOR XML PATH (''), type
     ) AS "To"
    ,(select top(1) 'Multi Value Text Sample'
      from [docMVtext] as C
      where C.[sID] = [sv].[sID] and c.fieldID = '130' ) as 'MVtext130/@DisplayName'
    ,(select top(1) 'MV'
      from [docMVtext] as C
      where C.[sID] = [sv].[sID] and c.fieldID = '130' ) as 'MVtext130/@SVMV'
    --,'Multi Value Text Sample' as 'MVtext130/@DisplayName'
    --,'MV' as 'MVtext130/@SVMV'    
    ,(SELECT  [value] AS 'value' 
       FROM  [docMVtext] as [mv]
       WHERE [mv].[sID] = [sv].[sID]
         AND [mv].[fieldID] = '130'
       ORDER BY [mv].[value]
       FOR XML PATH (''), type
     ) AS "MVtext130" 
  FROM  [docSVsys] as [sv]
  WHERE [sv].[sID] >= '57' 
  ORDER BY [sv].[sParID], [sv].[sID]
  FOR XML PATH('Document'), root('Documents')

最佳答案

不确定我是否理解您想要什么,并且如果没有您拥有的表格,很难用您的代码做一些事情,所以我创建了一个示例,我相信它正在做您已经拥有的事情。

设置表和数据:

declare @Main table
(
  MainID int identity,
  Value int
)

declare @Child table
(
  ChildID int identity,
  MainID int,
  Value int
)

insert into @Main values (10),(20),(30)
insert into @Child values (1,100),(2,200),(2,210)

与您的查询大致相同的查询。

select M.MainID as '@MainID',
       M.Value as 'MainValue',
       (select C.Value as ChildValue
        from @Child as C
        where C.MainID = M.MainID
        for xml path(''), type) as Child
from @Main as M
for xml path('Document'), root('Documents')

结果:

<Documents>
  <Document MainID="1">
    <MainValue>10</MainValue>
    <Child>
      <ChildValue>100</ChildValue>
    </Child>
  </Document>
  <Document MainID="2">
    <MainValue>20</MainValue>
    <Child>
      <ChildValue>200</ChildValue>
      <ChildValue>210</ChildValue>
    </Child>
  </Document>
  <Document MainID="3">
    <MainValue>30</MainValue>
  </Document>
</Documents>

我相信您的预期输出会像这样,在子节点上带有显示名称属性。

<Documents>
  <Document MainID="1">
    <MainValue>10</MainValue>
    <Child DisplayName="Child Display Name">
      <ChildValue>100</ChildValue>
    </Child>
  </Document>
  <Document MainID="2">
    <MainValue>20</MainValue>
    <Child DisplayName="Child Display Name">
      <ChildValue>200</ChildValue>
      <ChildValue>210</ChildValue>
    </Child>
  </Document>
  <Document MainID="3">
    <MainValue>30</MainValue>
  </Document>
</Documents>

要获得此查询,请改用此查询:

select M.MainID as '@MainID',
       M.Value as 'MainValue',
       (select top(1) 'Child Display Name'
        from @Child as C
        where C.MainID = M.MainID) as 'Child/@DisplayName',
       (select C.Value as ChildValue
        from @Child as C
        where C.MainID = M.MainID
        for xml path(''), type) as Child
from @Main as M
for xml path('Document'), root('Documents')

关于xml - TSQL FOR XML 路径属性,类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8492938/

有关xml - TSQL FOR XML 路径属性,类型的更多相关文章

  1. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  5. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  6. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  7. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  8. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

  9. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  10. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

    我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

随机推荐