我有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
是&#39; ccc&#39;。
以下是我的努力
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
但是,我收到错误说明
子查询返回的值超过1。当子查询遵循=,!=,&lt;,&lt; =,&gt;,&gt; =或子查询用作表达式时,不允许这样做。
任何人都可以指导如何实现我在这里尝试做的事情吗?
P.S稍后我也希望得到&#39;目标&#39;来自XML列的每一行,其中等效的user
是&#39; userA&#39;。
答案 0 :(得分:2)
(select prop1 from res1) prop1
这是导致错误的查询部分。如果要将其用作子查询,则必须为语句的每一行返回一行:
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经验的人可能能够提供更好的整体解决方案。
答案 1 :(得分:2)
如果我正确地得到了你正在创建一个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
会返回多个元素,因此不能在子选择中作为列调用...
...删除
你可能正在寻找这个:
这将使您自己加入TableC和TableA,然后选择“createdBy”的值,其中“type”=“ccc”。
下一个XQuery首先选择我们在第一次访问“ccc”时找到的用户名并找到拟合“目标”。
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