如何从 XML 列的元素列表中为每一行 select ?

How do I select for each row from a list of elements in an XML column?

我有 TableC 和 TableA。我想要 TableC 中的所有记录,而只匹配 TableA 中的记录,所以我使用 'left join'。 问题是 TableA 有一个 XML 列。该列中的 XML 具有以下结构

<x:main xmlns:x="x-elements">
  <x:rules>
    <x:obj>
        <ruleName>name1</ruleName>
        <createdBy>userA</createdBy>
        <type>bbb</type>
    </x:obj>
    <x:obj>
        <ruleName>name2</ruleName>
        <createdBy>userA</createdBy>
        <type>ccc</type>
    </x:obj>
   </x:rules>
   <x:info>
    <x:obj>
        <target>ftp:1</target>
        <user>userB</user>
    </x:obj>
    <x:obj>
        <target>ftp:3</target>
        <user>userA</user>
    </x:obj>
  </x:info>
</x:main>

我想从 XML 列的每一行中获取 createdBy,其中等效的 type 是 'ccc'。

下面是我的努力

with xmlnamespaces ('x-elements' as x),
res1 as (select x.xmlCol.value('(createdBy)[1]', 'varchar(500)') prop1
from TableC c 
left join TableA a 
cross apply a.xCol.nodes('x:main/x:rules/x:obj') x(xmlCol)
on c.Id = a.Id 
where x.xmlCol.value('(type)[1]', 'varchar(500)') = 'ccc')
select
c.Name,
(select prop1 from res1) prop1
from TableC c 
left join TableA a 
on c.Id = a.Id 

但是,我收到一条错误消息

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

任何人都可以指导如何实现我在这里尝试做的事情吗?

P.S 稍后我还想从 XML 列的每一行中获取 'target',其中等价的 user 是 'userA'.

(select prop1 from res1) prop1

这是导致错误的查询部分。如果您想将其用作子查询,它必须 return 一行对应您的语句的每一行:

select
c.Name,
(select prop1 from res1) prop1
from TableC c 
left join TableA a 
on c.Id = a.Id

我对 XML 查询一无所知,但为了使此查询有效,您需要向 res1 CTE 添加一个 ID。

res1 as (select x.xmlCol.value('(prop1)[1]', 'varchar(500)') prop1
,c.Id
from TableC c 
left join TableA a 
cross apply a.xCol.nodes('x:main/x:sub/x:obj') x(xmlCol)
on c.Id = a.Id 
where x.xmlCol.value('(prop2)[1]', 'varchar(500)') = 'ccc')

然后将子查询更改为:

(select prop1 from res1 where res1.Id = c.Id) prop1

我知道我的回答只解决了您问题的子查询部分,但我希望这有助于解决眼前的问题。如果没有 CTE,有更多查询经验的人 XML 可能能够提供更好的整体解决方案。

如果我没看错,你正在创建一个 CTE,你想,你需要这个来获得你的 prop1。然后您再次执行完全相同的联接和筛选...

将其减少到:

还不够吗?
with xmlnamespaces ('x-elements' as x)
select x.xmlCol.value('(prop1)[1]', 'varchar(500)') prop1
from TableC c 
left join TableA a 
cross apply a.xCol.nodes('x:main/x:sub/x:obj') x(xmlCol)
on c.Id = a.Id 
where x.xmlCol.value('(prop2)[1]', 'varchar(500)') = 'ccc'

正如 Arthur Daniels 指出的那样,问题是 (select prop1 from res1) prop1 将 return 多个元素,因此不能称为子 select 中的列。 .

编辑:如何切碎您的 XML

已删除....

编辑 2:我必须承认你真的应该训练 我如何解释我需要什么 ...

您可能正在寻找这个:

这将连接 TableC 和 TableA,就像您自己做的那样,然后选择“createdBy”的值,其中“type”=“ccc”。

下一个 XQuery 首先选择我们在第一次访问“ccc”时找到的用户名,然后找到合适的“target”。

WITH XMLNAMESPACES('x-elements' AS x)
SELECT c.*
      ,a.*
      ,a.xCol.value('(//x:rules/x:obj[type="ccc"]/createdBy)[1]','varchar(500)') AS CreatedBy
      ,a.xCol.value('let $user:=(//x:rules/x:obj[type="ccc"]/createdBy)[1] return (//x:info/x:obj[user=$user]/target)[1]','varchar(500)') AS Target
FROM TableC AS c 
LEFT JOIN TableA AS a on c.Id = a.Id