, поскольку результатом подзапроса является отношение
Отношение - это научное c имя для того, что мы называем таблицей в базе данных, и мне нравится Название «таблица» намного лучше, чем «отношение». Стол легко представить. Мы знаем их из нашего школьного расписания, например. Да, мы связываем вещи здесь внутри таблицы (день и время и предмет, преподаваемый в школе), но мы также можем связать таблицы с таблицами (расписание учеников с таблицей класса комнаты, общий предметный график и расписание учителя). Таким образом, таблицы в СУБД также связаны друг с другом (отсюда и название реляционная система управления базами данных). Я нахожу отношение имени для таблицы довольно запутанным (и многие люди используют вместо этого слово «отношение» для описания отношений между таблицами).
Итак, да, сам результат запроса опять таблица («отношение»). И, конечно, из таблиц мы можем выбрать:
select * from (select * from b) as subq;
И затем есть скалярные запросы, которые возвращают ровно одну строку и один столбец. select count(*) from b
такой запрос. Хотя это все еще таблица, которую мы можем выбрать из
select * from (select count(*) as cnt from b) as subq;
, мы даже можем использовать их там, где у нас обычно есть отдельные значения, например, в предложении select:
select a.*, (select count(*) from b) as cnt from a;
В вашем запросе вы У вас есть два скалярных подзапроса в вашем предложении where.
С подзапросами нужно сделать еще одно различие: у нас есть коррелированные и некоррелированные подзапросы. Последний запрос, который я только что показал, содержит некоррелированный подзапрос. Он выбирает количество b строк для каждой строки результата, независимо от того, что эта строка содержит в противном случае. С другой стороны, коррелированный подзапрос может выглядеть так:
select a.*, (select count(*) from b where b.x = a.y) as cnt from a;
Здесь подзапрос связан с основной таблицей. Для каждой строки результата мы ищем количество строк b, соответствующих строке, которую мы отображаем, с помощью where b.x = a.y
, поэтому число отличается от строки к строке (но мы получили бы одинаковое количество строк, имеющих одинаковое значение y ).
Ваши подзапросы также коррелированы. Как и в случае с предложением select, предложение where имеет дело с одной строкой за раз (для ее сохранения или отклонения). Итак, мы смотрим на одного студента S1 одновременно. Для этого студента мы учитываем других студентов (S2, where S2.sID <> S1.sID
), которые имеют тот же средний балл (and S2.GPA = S1.GPA
), и считаем других студентов, имеющих тот же размер HS. Мы оставляем учеников (S1) там, где есть ровно столько же учеников с тем же GPA, сколько и с таким же размером HS.
ОБНОВЛЕНИЕ
Как и в случае с несколькими кортежами: в
select *
from Student S1
where (
select count(*), avg(grade)
from Student S2
where S2.sID <> S1.sID and S2.GPA = S1.GPA
) = (
select count(*), avg(grade)
from Student S2
where S2.sID <> S1.sID and S2.sizeHS = S1.sizeHS
);
это возможно в некоторых СУБД, но не в SQL Server. SQL Сервер не знает кортежей.
Но есть и другие способы добиться того же. Вы можете просто добавить два подзапроса:
select * from student s1
where (...) = (...) -- compare counts here
and (...) = (...) -- compare averages here
или получить данные в предложении FROM
, а затем обработать их. Например:
select *
from Student S1
cross apply
(
select count(*) as cnt, avg(grade) as avg_grade
from Student S2
where S2.sID <> S1.sID and S2.GPA = S1.GPA
) sx
cross apply
(
select count(*) as cnt, avg(grade) as avg_grade
from Student S2
where S2.sID <> S1.sID and S2.sizeHS = S1.sizeHS
) sy
where sx.cnt = sy.cnt and sx.avg_grade = sy.avg_grade;