SQL: добавление к имени поля идентификатора подзапроса приводит к тому, что подзапрос должен быть оценен первым? - PullRequest
0 голосов
/ 26 мая 2020

Мой вопрос не в понимании того, что происходит (возможно, в различных реализациях) в следующих запросах. Вместо этого речь идет о понимании того, определяет ли стандарт SQL правильное поведение.

Простая таблица с отрицательными и положительными целыми числами:

CREATE TABLE x (n INTEGER);

INSERT INTO x VALUES (-2);
INSERT INTO x VALUES (-1);
INSERT INTO x VALUES (0);
INSERT INTO x VALUES (1);
INSERT INTO x VALUES (2);

Сначала возьмите этот запрос:

select n
from x 
where n <> 0 
and   1/n = 1;

Очевидно, что ожидаемый порядок интеллектуальной оценки точно такой, как он записан в запросе, чтобы избежать вычисления 1/0, что могло бы вызвать ошибку.

Однако, SQL - это декларативный язык запросов, и, как уже было рассмотрено в нескольких вопросах, порядок предложений where не имеет значения, поэтому их можно оценивать в любом порядке, что означает, что может произойти ошибка деления на 0 и все будет в порядке. Это ясно.

Теперь второй пример:

select nonzero.n
from (select n from x where n <> 0) as nonzero
where 1/nonzero.n = 1;

Логически то же самое с точки зрения предложений where в таблице x, но они организованы по-разному. На этот раз я определяю отношение, которое не может иметь нулей. Основной запрос явно вычисляет 1/nonzero.n, поэтому я интуитивно ожидал, что движок будет применять здесь порядок оценки, и не увижу никакого деления на 0.

Обратите внимание, что это не единственный вариант оценки, который я видел на практике. Некоторые движки SQL сначала сглаживают второй запрос обратно к первому.

Независимо от того, что делают разные реализации, мой вопрос: применяется ли SQL стандарт каким-либо образом, когда я пишу nonzero.n тогда n действительно взято из отношения nonzero, а не из x, которые, очевидно, не эквивалентны? Если да, знаете ли вы какой-нибудь указатель на то, где это выражено формально?

1 Ответ

0 голосов
/ 26 мая 2020

В стандарте не указано, что делать. Он довольно слабо обрабатывает ошибки. select. Запрос в целом описывает набор результатов, а не пошаговые инструкции по его созданию.

Это сделано намеренно. Люди, которые пишут стандарт, знают, что план выполнения обычно представляет собой ориентированный ациклический c граф (DAG), который не имеет ничего общего с исходным запросом (кроме его реализации!).

Обратите внимание, что есть случаи, когда 1/0 вообще не оценивается. Доступ к некоторым базам данных:

where exists (select 1 / 0
              from t
              where . . .
             )

Exists заботится только о том, возвращаются ли строки, а не о том, какие значения находятся в этих строках.

...