У меня есть TableC и TableA. Мне нужны все записи из TableC, тогда как только совпадающие записи из TableA, поэтому я использую «левое соединение». Проблема в том, что в 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>
Я хочу получить createdBy
из столбца XML для каждой строки, где эквивалентным 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
Однако я получаю сообщение об ошибке
Подзапрос вернул более одного значения. Это не разрешено, если подзапрос следует за =,! =, <, <=,>,> = Или когда подзапрос используется как выражение.
Может ли кто-нибудь рассказать, как достичь того, что я пытаюсь сделать здесь?
P.S Позже я также хотел бы получить «цель» из столбца XML для каждой строки, где эквивалент user
- «userA».
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, но для того, чтобы этот запрос работал, вам нужно будет добавить идентификатор в CTE res1.
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
Я понимаю, что мой ответ решает только часть подзапроса вашего вопроса, но я надеюсь, что это поможет решить ближайшую проблему. Кто-то, у кого больше опыта в запросах XML, может предоставить лучшее общее решение без CTE.
Если я понял это правильно, вы создаете 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'
Как указал Артур Дэниэлс, проблема заключается в том, что (select prop1 from res1) prop1
будет возвращать более одного элемента и, следовательно, не может быть вызван как столбец в подвыборке ...
РЕДАКТИРОВАТЬ: как измельчить ваш XML
Удалено ....
РЕДАКТИРОВАТЬ 2: Я должен признать, что вам действительно стоит потренироваться как мне объяснить, что мне нужно ...
Возможно, вы ищете это:
Это объединит TableS и TableS, как вы это сделали сами, а затем выберите значение «created By», где «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
Похожие вопросы
Связанные вопросы
Новые вопросы
sql-server
Microsoft SQL Server — это система управления реляционными базами данных (RDBMS). Используйте этот тег для всех выпусков Microsoft SQL Server, включая Compact, Express, Azure, Fast-track, APS (ранее PDW) и Azure SQL DW. Не используйте этот тег для других типов СУБД (MySQL, PostgreSQL, Oracle и т. д.). Не используйте этот тег для вопросов по программному обеспечению и разработке мобильных устройств, если только он не связан напрямую с базой данных.