Получение отдельных записей из объединенных таблиц, которые могут создавать несколько записей
-
03-07-2019 - |
Вопрос
У меня есть стол для студентов и стол для зачисления;студент может иметь несколько записей о зачислении, которые могут быть активными или неактивными.
Я хочу получить выборку с одной записью учащегося и индикатором того, есть ли у этого учащегося активные зачисления.
Я думал сделать это во встроенной пользовательской функции, которая использует идентификатор студента при соединении с таблицей регистрации, но мне интересно, есть ли лучший способ сделать это в одном операторе выбора.
Вызов UDF может выглядеть примерно так:
Select Student_Name,Student_Email,isEnrolled(Student_ID) from Student
Как могла бы выглядеть альтернатива с одним оператором SQL?
Решение
select Student_Name,
Student_Email,
(select count(*)
from Enrollment e
where e.student_id = s.student_id
) Number_Of_Enrollments
from Student e
получит количество зачислений, что должно помочь.
Другие советы
Почему бы не присоединиться к вторичному выбору?В отличие от других решений, это не запускает подзапрос для каждой возвращаемой строки, а собирает данные о регистрации для всех сразу.Синтаксис может быть не совсем правильным, но вы должны уловить идею.
SELECT
s.student_name,
s.student_email,
IsNull( e.enrollment_count, 0 )
FROM
Students s
LEFT OUTER JOIN (
SELECT
student_id,
count(*) as enrollment_count
FROM
enrollments
WHERE
active = 1
GROUP BY
student_id
) e
ON s.student_id = e.student_id
Выбор из регистраций также можно переделать в функцию, которая возвращает таблицу, к которой вы можете присоединиться.
CREATE FUNCTION getAllEnrollmentsGroupedByStudent()
RETURNS @enrollments TABLE
(
student_id int,
enrollment_count int
) AS BEGIN
INSERT INTO
@enrollments
(
student_id,
enrollment_count
) SELECT
student_id,
count(*) as enrollment_count
FROM
enrollments
WHERE
active = 1
GROUP BY
student_id
RETURN
END
SELECT
s.student_name,
s.student_email,
e.enrollment_count
FROM
Students s
JOIN
dbo.getAllEnrollmentsGroupedByStudent() e
ON s.student_id = e.student_id
Редактировать:
Ренце де Ваал исправил мой плохой SQL!
Попробуйте что-нибудь вроде этого:
SELECT Student_Name, Student_Email, CAST((SELECT TOP 1 1 FROM Enrollments e WHERE e.student_id=s.student_id) as bit) as enrolled FROM Student s
Я думаю, вы также можете использовать оператор существования в выборе, но не в положительном
старайтесь избегать использования udfs или подзапросов, они снижают производительность.В противном случае у Banjoility, кажется, есть хорошее решение, поскольку он использует таблицу производных вместо UDF или подвыборки.
select students.name,
decode(count(1), 0, "no enrollments", "has enrollments")
from students, enrollments
where
students.id = enrollments.sutdent_id and
enrollments.is_active = 1 group by students.name
Конечно, замените декодирование функцией, которую использует ваша база данных (или оператором случая).