#sql #sql-server #xml #subquery
Вопрос:
У меня возникли некоторые проблемы с запросом для получения некоторой информации
select id_column, d_description
from table1
where (select substring(cast(g_xml_comprobante as nvarchar(max)), charindex('contrato=', cast(g_xml_comprobante as nvarchar(max))) 10, 15) as 'contract'
from table1 a, table 3 b
where convert(varchar(6), b.d_date, 112) > '202108'
and b.id_column = a.id_column) = '2019896177'
Я получаю эту ошибку:
Msg 512, Уровень 16, Состояние 1,
Подзапрос строки 1 вернул более 1 значения. Это недопустимо, если подзапрос следует =, !=, <, <= , >, <= , >>= или когда подзапрос используется в качестве выражения.
Ситуация выглядит так: у нас есть XML — информация в столбце внутри таблицы1, в XML у нас есть номер контракта. Итак, я хочу получить все идентификаторы из определенных контрактов, у меня есть значения контрактов, поэтому мне нужно, чтобы это было где.
Возможно ли это осуществить?
Если мне не ясно, пожалуйста, дайте мне знать, чтобы я мог уточнить.
Спасибо за помощь!
Комментарии:
1. Вредные привычки : использование соединений в старом стиле -этот стиль списка таблиц, разделенных запятыми в старом стиле, был заменен правильным
JOIN
синтаксисом ANSI в стандарте SQL ANSI — 92 ( почти 30 лет назад), и его использование не рекомендуется
Ответ №1:
То, что написал Серж, тоже верно. Но если вы просто проверяете, что конкретный идентификатор контракта существует в вашем подзапросе, и по какой-то причине несколько строк имеют один и тот же контракт, то вы можете сделать следующее. Вы можете использовать в предложении, как показано ниже
select id_column, d_description
from table1
where '2019896177' in (select substring(CAST(g_xml_comprobante as nvarchar(max)),CHARINDEX('contrato=',CAST(g_xml_comprobante as nvarchar(max))) 10,15) as 'contract' from table1 a,table3 b
where convert(varchar(6),b.d_date,112) > '202108' and b.id_column=a.id_column
)
однако второй подход, который довольно распространен при работе с ошибками такого типа, но в основном зависит от ваших данных, какие данные возвращаются.
если ваш подзапрос возвращает одинаковое значение для всех строк, то лучше всего использовать Top 1
его в вашем подзапросе.
select id_column, d_description
from table1
where (select Top 1 substring(CAST(g_xml_comprobante as nvarchar(max)),CHARINDEX('contrato=',CAST(g_xml_comprobante as nvarchar(max))) 10,15) as 'contract' from table1 a,table3 b
where convert(varchar(6),b.d_date,112) > '202108' and b.id_column=a.id_column
)='2019896177'
Ответ №2:
В вашем запросе есть ряд проблем:
- Ваша основная проблема: вы выполняете запрос
table1
во второй раз, снова соединяя всю таблицу. - Следствие этого
table3
также может иметь несколько результатов. Так что вам действительно нужноEXISTS
здесь. - Кроме того, вы можете использовать XQuery для анализа XML вместо ужасных манипуляций со строками
- Даты следует запрашивать с помощью диапазонов дат, и если вам действительно нужно было сократить компонент времени, вы можете использовать
cast( ... as date)
- Всегда используйте правильный синтаксис соединения, а не устаревшее соединение через запятую в старом стиле
- Сделайте ваши запросы читабельными: используйте пробелы, это бесплатно
- Используйте разумные псевдонимы таблиц, а не бессмысленные
a
b
c
select
t1.id_column,
t1.d_description
from table1 t1
where exist (select 1
from [table 3] t3
where t3.d_date > '202108'
and t3.id_column = t1.id_column
-- not sure exactly what XQuery you are looking for
and t3.g_xml_comprobante.exist('//@contrato[. = "2019896177"]') = 1
);
Ответ №3:
Вы пытаетесь сравнить результаты подзапроса с константой. Но ваш подзапрос возвращает более одного значения. В таком случае вы можете использовать ЛЮБОЙ или ВСЕ до подзапроса. ЛЮБОЕ означает, что результат является истинным, если какое-либо из возвращаемых значений соответствует условию. ВСЕ это означает, что результат является истинным, если все возвращаемые значения соответствуют условию.