Я не уверен, как важна причина; Это так, и зная, почему это не изменится.
Поскольку SQL является декларативным, существуют правила, касающиеся области действия, порядка выполнения, порядка приоритета и т. Д. Правила, которые позволяют планировщику на основе затрат создавать план, который фактически будет выполняться. Одним из таких правил является то, что вы не можете оценить два независимых запроса в одном наборе. Даже если бы T
была таблицей материалов, двойная ссылка на нее привела бы в план как два независимых набора.
Вместо этого вам нужен другой способ выразить свое требование, больше соответствующее языку. Тот, где вы не пытаетесь анализировать один и тот же набор несколько раз.
Например, вы можете приобрести два комплекта из одного и того же выражения таким образом ...
WITH
T AS
(
SELECT * FROM Grades WHERE dept_id = 'MT'
)
SELECT DISTINCT student_id
FROM T
WHERE grade = (SELECT MAX(grade) FROM T);
Или вы можете использовать оконные функции и позволить внутреннему движку определить, как наилучшим образом оценить все условия с минимальными затратами ...
SELECT
*
FROM
(
SELECT
Grades.*,
MAX(grade) OVER () AS max_grade
FROM
Grades
WHERE
dept_id = 'MT'
)
T
WHERE
grade = max_grade
1024 *
*
ОЧЕНЬ ДЛИННОЕ РЕДАКТИРОВАНИЕ: Субъективные и объективные аргументы против предложения
Предполагается, что наборы, определенные во внешних запросах, могут использоваться как независимые наборы во внутренних запросах.
SELECT DISTINCT
student_id
FROM
(
SELECT * FROM Grades WHERE dept_id = 'MT'
)
newSetDefinition
WHERE
grade = (SELECT MAX(grade) FROM newSetDefinition)
-----------------------------
Functionally Equivalent To...
-----------------------------
WITH
newSetDefinition
AS
(
SELECT * FROM Grades WHERE dept_id = 'MT'
)
SELECT DISTINCT
student_id
FROM
newSetDefinition
WHERE
grade = (SELECT MAX(grade) FROM newSetDefinition)
Это подразумевает, что следующее также должно работать ...
SELECT DISTINCT
newSetDefinition.student_id
FROM
(
SELECT * FROM Grades WHERE dept_id = 'MT'
)
newSetDefinition
INNER JOIN
(
SELECT MAX(grade) AS maxGrade FROM newSetDefinition
)
newSetSummary
ON newSetSummary.maxGrade = newSetDefinition.grade
-----------------------------
Functionally Equivalent To...
-----------------------------
WITH
newSetDefinition
AS
(
SELECT * FROM Grades WHERE dept_id = 'MT'
)
SELECT DISTINCT
newSetDefinition.student_id
FROM
newSetDefinition
INNER JOIN
(
SELECT MAX(grade) AS maxGrade FROM newSetDefinition
)
newSetSummary
ON newSetSummary.maxGrade = newSetDefinition.grade
Пока все хорошо ...
С вложенными запросами это становится немного опаснее, поскольку следующее невозможно точно представить с помощью CTE из-за различной доступности области действия и конфликтов имен. Становится необходимым определить CTE внутри подзапросов ...
SELECT
*
FROM
(
SELECT * FROM table WHERE something = 1
)
smeg
INNER JOIN
(
SELECT
*
FROM
(
SELECT * FROM table WHERE somethingElse = 2
)
smeg
INNER JOIN
(
SELECT MAX(id) AS maxID FROM smeg
)
smegSummary
ON smegSummary.maxID = smeg.ID
)
smegSubSet
ON smegSubSet.parentID = smeg.ID
-----------------------------
Functionally Equivalent To...
-----------------------------
WITH
smeg AS
(
SELECT * FROM table WHERE something = 1
)
SELECT
*
FROM
smeg
INNER JOIN
(
WITH
smeg AS
(
SELECT * FROM table WHERE something = 1
)
SELECT
*
FROM
smeg
INNER JOIN
(
SELECT MAX(id) AS maxID FROM smeg
)
smegSummary
ON smegSummary.maxID = smeg.ID
)
smegSubSet
ON smegSubSet.parentID = smeg.ID
Хорошо, так что все в порядке, просто немного неопрятно. CTE помогают избежать необходимости глубокого вложения, поэтому наличие вложенного синтаксиса для CTE «грязно», но даже это субъективная мера.
Когда вы видите «набор ссылок», вы обращаетесь к внешним запросам, пока не найдете набор с таким псевдонимом, и если ни один из них не найден, используйте обычные правила; CTES, затем таблицы / представления в текущей схеме, затем таблицы / представления в текущей базе данных, но другая схема, все с учетом разрешений и т. Д.
Прекрасные, довольно стандартные правила определения объема.
Но следующий сценарий более объективно проблематичен ...
SELECT
*
FROM
(
SELECT * FROM smeg WHERE something = 1
)
smeg
В текущем ANSI-SQL это нормально, если есть таблица с именем smeg
.
В AlwaysLearning-SQL это циклическая ссылка. «Ближайшее» определение для smeg
- это внешний запрос. Это «переопределяет» любые таблицы или представления с именем smeg
. Итак, внутренний запрос теперь выбирается из ... самого себя ...
Есть аргумент, чтобы сказать "просто позвольте этому вызвать ошибку круговой ссылки".
Но это нарушает обратную совместимость.
Представьте себе, если Oracle добавил эту функциональность в v13? Все неожиданные запросы, которые раньше работали, начинают вызывать ошибки циклических ссылок? Зачем? Чтобы некоторые подзапросы работали как CTE, при условии, что это полезно / удобно? To make some aspects of life "convenient" we broke some of your queries.
Произошло нарушение обратной совместимости. Но только когда выгоды далеко перевешивают последствия.
В этом случае все, что , что может быть сделано с вашим предложением, может быть сделано с CTE. И CTE были добавлены без нарушения привычного поведения. И (субъективно / возможно) CTE могут сделать это более структурированным, более понятным, простым для чтения, простым в отладке и т. Д.
Лично я очень рад, что никто еще не сломал некоторые запросы для реализации какой-то очень нишевой функциональности.