Select Stateemt 中动态 SQL 变量的 XQuery [value()] 问题

问题描述

我正在尝试使下面的代码动态化,因为页面“节点”中的“名称属性可以有不同的名称

当我运行下面的代码时,它返回错误 'XQuery [value()]: 'value()' requires a singleton (or empty sequence),found operand of type 'xdt:untypedAtomic *''

我觉得我的主要问题是在线 'C.value('(/level1/level2/template/page/@name)[sql:variable("@Counter")]','NVARCHAR(MAX)') AS [页面名称]' 我试图使 '@counter' 变量动态化。

请问大家有什么解决办法吗?

XML FOR ID 9371

<level1>
  <level2>
    <template width="594" height="500">
      <page Cid="1" name="Test Page Name" colour="-3355393">
        <image Cid="8" x="432" y="8" w="148" h="95" KeyImage="32861" Ratio="y" />
        <formattedText Cid="14" x="9" y="22" w="253" h="38">
          <p>
            <p>
              Text
            </p>
          </p>
        </formattedText>
      </page>
      <page Cid="6" name="Properties">
        <formattedText Cid="7" x="200" y="148" w="208" h="228">
          <p>
            <p>
              <t>Created by </t>
              <t b="b">Joe Bloggs</t>
            </p>
            <p />
            <p>
              <t>Date published 30/05/2017</t>
            </p>
        </formattedText>
      </page>
    </template>
  </level2>
</level1>

sql 查询的结果

** 呈现结果

Page Name   | Demographics  
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Test Page Name  | <page Cid="1" name="Test Page Name" colour="-3355393"><image Cid="8" x="432" y="8" w="148" h="95" KeyImage="32861" Ratio="y" /><formattedText Cid="14" x="9" y="22" w="253" h="38"><p><p>Text</p></p> </formattedText></page>
Test Page Name  | <page><formattedText Cid="7" x="200" y="148" w="208" h="228"><p><p> <t>Created by </t><t b="b">Joe Bloggs</t></p><p /><p><t>Date published 30/05/2017</t> </p></formattedText></page> 

** 想要的结果

Page Name   | Demographics  
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Test Page Name  | <page Cid="1" name="Test Page Name" colour="-3355393"><image Cid="8" x="432" y="8" w="148" h="95" KeyImage="32861" Ratio="y" /><formattedText Cid="14" x="9" y="22" w="253" h="38"><p><p>Text</p></p> </formattedText></page>
Properties  | <page><formattedText Cid="7" x="200" y="148" w="208" h="228"><p><p> <t>Created by </t><t b="b">Joe Bloggs</t></p><p /><p><t>Date published 30/05/2017</t> </p></formattedText></page> 



DECLARE @TableName VARCHAR(40),@opxml AS XML,@hDoc AS INT,@sql NVARCHAR (MAX)
   


SELECT @opxml = 
a.[filedata]
FROM [database].[dbo].[xmlfile2] a
where  [Id] = 9371

DECLARE @Counter INT 
DECLARE @MaxNo INT 
SET @Counter=1
SET @MaxNo=(SELECT
COUNT(CAST('<page>' +  CAST(C.query('./child::node()') as nvarchar(max)) + '</page>' as xml))
FROM @opxml.nodes('/level1/level2/template/page') AS T(C))

WHILE ( @Counter <= @MaxNo)
BEGIN

SELECT
C.value('(/level1/level2/template/page/@name)[sql:variable("@Counter")]','NVARCHAR(MAX)') AS         
[Page Name],CAST('<page>' +  CAST(C.query('./child::node()') as nvarchar(max)) + '</page>' as xml) AS     [Page_XML],ROW_NUMBER() OVER (ORDER BY t.c)
FROM @opxml.nodes('/level1/level2/template/page') AS T(C)


SET @Counter  = @Counter  + 1
END

解决方法

我觉得

SELECT
  C.value('@name','NVARCHAR(MAX)') AS [Page Name],C.query('<page>{node()}</page>') AS [Page_XML],ROW_NUMBER() OVER (ORDER BY t.c)
FROM @opxml.nodes('/level1/level2/template/page') AS T(C)

可能足以产生所需的结果,而无需 WHILE 循环。

我认为value()(例如C.value('(/level1/level2/template/page/@name)[sql:variable("@Counter")]','NVARCHAR(MAX)'))内部的长路径的原始问题是由于SQL服务器中XQuery的静态类型检查,为了避免它,您基本上需要添加另一个谓词确保类型检查器知道返回单个值,例如C.value('(/level1/level2/template/page/@name)[sql:variable("@Counter")][1]','NVARCHAR(MAX)')

对我来说,代码

DECLARE @opxml AS XML

SET @opxml = N'<level1>
  <level2>
    <template width="594" height="500">
      <page Cid="1" name="Test Page Name" colour="-3355393">
        <image Cid="8" x="432" y="8" w="148" h="95" KeyImage="32861" Ratio="y" />
        <formattedText Cid="14" x="9" y="22" w="253" h="38">
          <p>
            <p>
              Text
            </p>
          </p>
        </formattedText>
      </page>
      <page Cid="6" name="Properties">
        <formattedText Cid="7" x="200" y="148" w="208" h="228">
          <p>
            <p>
              <t>Created by </t>
              <t b="b">Joe Bloggs</t>
            </p>
            <p />
            <p>
              <t>Date published 30/05/2017</t>
            </p>
          </p>
        </formattedText>
      </page>
    </template>
  </level2>
</level1>'

SELECT
  C.value('@name',ROW_NUMBER() OVER (ORDER BY t.c)
FROM @opxml.nodes('/level1/level2/template/page') AS T(C)

制作桌子

Page Name   Page_XML    (Kein Spaltenname)
Test Page Name  <page><image Cid="8" x="432" y="8" w="148" h="95" KeyImage="32861" Ratio="y" /><formattedText Cid="14" x="9" y="22" w="253" h="38"><p><p>
              Text
            </p></p></formattedText></page> 1
Properties  <page><formattedText Cid="7" x="200" y="148" w="208" h="228"><p><p><t>Created by </t><t b="b">Joe Bloggs</t></p><p /><p><t>Date published 30/05/2017</t></p></p></formattedText></page> 2

所以至少 Page_Name 似乎很容易通过使用例如C.value('@name','NVARCHAR(MAX)') AS [Page Name]