ВведениеSQL скалярная подзапрос проверки строки был найден
Иногда вместо объединения можно сознательно использовать скалярный подзапрос, чтобы проверить, что не более чем одна строка была найдена. Например, у вас может быть этот запрос, чтобы найти национальность для некоторых строк person
.
select p.name, c.iso from person p join person_country_map pcm on p.id = pcm.person join country c on pcm.country = c.id where p.id in (1, 2, 3)
Теперь предположим, что person_country_map
не является функциональным отображением. Данный человек может отображаться более чем в одной стране, поэтому в объединении может быть найдено несколько строк. Или, действительно, человек не может быть в таблице сопоставления вообще, по крайней мере, в отношении любых ограничений базы данных.
Но для данный конкретный вопрос Я знаю, что люди, которых я запрашиваю, будут иметь ровно одну страну. Это предположение, что я основываю свой код на. Но я хотел бы проверить это предположение, когда это возможно, чтобы, если что-то пошло не так, и я в конечном итоге попытаюсь сделать этот запрос для человека с более чем одной страной или без какой-либо страны, отображающей строку, он умрет.
Добавление проверки безопасности для не более чем одной строки
Для проверки более одной строки, вы можете переписать присоединиться в качестве скалярного подзапроса:
select p.name, ( select c.iso from person_country_map pcm join country c on pc.country = c.id where pcm.person = p.id ) as iso from person p where p.id in (1, 2, 3)
Теперь СУБД дать ошибку, если человек запросил карты для двух или более стран. Он не будет возвращать несколько записей для одного и того же человека, так как прямое соединение будет. Поэтому я могу спать немного легче, зная, что этот случай ошибки проверяется даже до того, как любые строки будут возвращены в приложение. Разумеется, в качестве осторожного программиста я могу проверить приложение.
Можно ли иметь проверку безопасности длянетстрок нашли?
Но как насчет того, нет ли строки в person_country_map для человека? Скалярный подзапрос в этом случае возвращает null, что делает его примерно эквивалентным левому соединению.
(ради аргумента предположим, внешний ключ от person_country_map.country к country.id и уникальный индекс country.id так, чтобы присоединиться частности всегда будет успешным и найти ровно одну строку страны.)
Мой вопрос
Есть ли способ выразить в SQL, что я хочу один и ровно один результат? Простой скалярный подзапрос равен «ноль или один». Я хотел бы быть в состоянии сказать
select 42, (select exactly one x from t where id = 55)
и есть запрос сбой во время выполнения, если подзапрос не возвращает строку. Конечно, вышеупомянутый синтаксис вымышленный, и я уверен, что это будет не так просто.
Я использую MSSQL 2008 R2, и на самом деле этот код хранится в процедуре, поэтому при необходимости я могу использовать TSQL. (Очевидно, что обычный декларативный SQL является предпочтительным, поскольку он также может использоваться в определениях определения.) Конечно, я могу сделать проверку exists
, или я могу выбрать значение в TSQL-переменной, а затем явно проверить его на nullness и т. Д. Я даже мог выбрать результаты во временную таблицу, а затем создавать уникальные индексы на этой таблице в качестве проверки. Но нет ли более читаемого и элегантного способа отметить мое предположение, что подзапрос возвращает ровно одну строку и имеет ли это допущение, проверенное СУБД?
Вы считали пользовательскую функцию, которая генерирует исключение, если не существует одного результата? – HABO
@HABO, вы имеете в виду общую функцию check_not_null (x), которая возвращает x, если x не является нулевым, и barfs (путем запуска деления на ноль, скажем) в противном случае? –
Я думал о 'GetCountryForUser (UserId)'. Он либо возвращает уникальный «CountryId» для указанного пользователя, либо жалуется. К сожалению, 'RaIsError' и' Throw' не разрешены в UDF, поэтому у вас осталось что-то вроде [this] (http://stackoverflow.com/questions/1485034/how-to-report-an-error-from- а-SQL-сервер, определяемый пользователь-функция). – HABO