如何从 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
我有 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