Вопрос по теории SQL-запросов - запросы с одним оператором против запросов с несколькими операторами
-
19-09-2019 - |
Вопрос
Когда я пишу SQL-запросы, я часто ловлю себя на мысли, что "нет никакого способа сделать это с помощью одного запроса".Когда это происходит, я часто обращаюсь к хранимым процедурам или многозначным табличным функциям с несколькими инструкциями, которые используют временные таблицы (того или иного вида) и в конечном итоге просто объединяют результаты и возвращают результирующую таблицу.
Мне интересно, знает ли кто-нибудь, просто теоретически, является ли это следует быть возможным написать ЛЮБОЙ запрос, который возвращает один результирующий набор, в виде одного запроса (а не нескольких инструкций).Очевидно, что я игнорирую важные моменты, такие как читаемость кода и ремонтопригодность, возможно, даже производительность запросов.Это больше о теории - можно ли это сделать...и не волнуйтесь, я, конечно, не планирую заставлять себя писать запрос с одним оператором, когда во всех случаях для моих целей лучше подойдет запрос с несколькими операторами, но это может заставить меня дважды или чуть дольше подумать о том, существует ли жизнеспособный способ получить результат из одного запроса.
Я предполагаю, что несколько параметров в порядке - я имею в виду реляционную базу данных (такую как MS SQL) с таблицами, которые соответствуют общепринятым рекомендациям (например, все таблицы имеют первичный ключ и так далее).
Примечание:чтобы получить "Принятый ответ" на этот вопрос, вам нужно будет предоставить окончательное доказательство (ссылку на веб-материал или что-то подобное).)
Решение
По крайней мере, с последней версией Oracle это абсолютно возможно.В нем есть "модельное предложение", которое делает sql turing завершенным.( http://blog.schauderhaft.de/2009/06/18/building-a-turing-engine-in-oracle-sql-using-the-model-clause/ ).Конечно, все это с обычным ограничением в том, что на самом деле у нас нет неограниченного времени и памяти.
Для обычного диалекта sql без этих дополнений я не думаю, что это возможно.
Задача, которую я не вижу, как реализовать в "обычном sql", была бы:Предположим, что имеется таблица с одним столбцом типа integer
Для каждой строки 'возьмите значение в текущей строке и вернитесь на столько строк назад, извлеките это значение, вернитесь на столько строк назад и продолжайте, пока не получите одно и то же значение дважды подряд и не вернете его в качестве результата.'
Другие советы
Я верю, что это возможно.Я работал с очень сложными запросами, очень длинными запросами, и часто это можно сделать с помощью одного запроса.Но в большинстве случаев это сложнее выполнить, поэтому, если вы делаете это с помощью одного запроса, обязательно тщательно прокомментируйте свой запрос.
Я никогда не сталкивался с чем-то, что не могло быть выполнено в одном запросе.
Но иногда лучше всего сделать это в нескольких запросах.
Я не могу это доказать, но я полагаю, что ответом будет осторожное "да" - при условии, что дизайн вашей базы данных выполнен должным образом.Обычно необходимость писать несколько инструкций для получения определенного результата является признаком того, что ваша схема может нуждаться в некоторых улучшениях.
Я бы сказал "да", но не могу этого доказать.Однако мой основной мыслительный процесс:
Любой выбор должен быть операцией, основанной на наборе
Ваше предположение заключается в том, что вы имеете дело с математически правильными наборами (т. е. правильно нормализованными)
Теория множеств должна гарантировать, что это возможно
Другие мысли:
Оператор множественного выбора часто загружает временные таблицы / табличные переменные.Они могут быть производными или разделены в CTE.
Любая обработка RBAR (хорошая или плохая) теперь обрабатывается ПЕРЕКРЕСТНЫМ / ВНЕШНИМ применением к производным таблицам
Мне кажется, в этом контексте UDFS был бы классифицирован как "обман", потому что он позволяет вам поместить SELECT в другой модуль, а не в ваш единственный
В вашей последовательности DML "до" записи запрещены:это изменяет состояние с SELECT на SELECT
Вы видели какой-нибудь код в нашем магазине?
Редактировать, глоссарий
- RBAR = Ряд За Мучительным Рядом
- CTE = Общее табличное выражение
- UDF = Определяемая пользователем Функция
Редактировать:ПРИМЕНЯТЬ:изменяешь?
SELECT
*
FROM
MyTable1 t1
CROSS APPLY
(
SELECT * FROM MyTable2 t2
WHERE t1.something = t2.something
) t2
Теоретически да, если вы используете функции или извилистый лабиринт ВНЕШНИХ приложений или подзапросов;однако для удобства чтения и производительности мы всегда в конечном итоге использовали временные таблицы и хранимые процедуры с несколькими операторами.
Как кто-то прокомментировал выше, обычно это признак того, что ваша структура данных начинает попахивать;не то чтобы это плохой, но, возможно, пришло время денормализовать из соображений производительности (случается с лучшими из нас), или, может быть, поместить денормализованный слой запросов перед вашими нормализованными "реальными" данными.