Obtendo registros únicos de volta de tabelas associadas que podem produzir vários registros
-
03-07-2019 - |
Pergunta
Eu tenho uma mesa de estudante e uma mesa de inscrição; um estudante pode ter vários registros de inscrição que pode ser ativo ou inativo.
Eu quero ter uma escolha que tem um único registro de estudante e um indicador para saber se esse aluno tem inscrições ativas.
Eu pensei em fazer isso em um UDF embutido que usa a identificação do aluno em uma junção com a tabela de inscrição, mas gostaria de saber se há uma maneira melhor de fazê-lo em uma única instrução SELECT.
A chamada UDF poderia ser algo como:
Select Student_Name,Student_Email,isEnrolled(Student_ID) from Student
O que pode a alternativa - com uma instrução SQL -? Parecido com
Solução
select Student_Name,
Student_Email,
(select count(*)
from Enrollment e
where e.student_id = s.student_id
) Number_Of_Enrollments
from Student e
obterá o número de matrículas, o que deve ajudar.
Outras dicas
Por que não juntar a um seleto secundária? Ao contrário de outras soluções, isso não está disparando uma subconsulta para cada linha retornada, mas reúne os dados de matrícula para todos de uma só vez. A sintaxe pode não ser muito correto, mas você deve ficar com a ideia.
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
O seleto de matrículas também poderia ser refeito como uma função que retorna uma tabela para você participar na.
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
Editar:
Renze de Waal corrigido meu mau SQL!
Tente algo parecido com isto:
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
Eu acho que você também pode usar a declaração existe no seleto, mas não positivo
tentar evitar o uso udfs ou subqueries, eles são assassinos de desempenho. banjolity parece solução havea boa de outra forma, porque ele usa uma tabela derivd em vez de uma UDF ou subselect.
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
É claro, substitua a decodificação com uma função de seus usos de banco de dados (ou, uma instrução CASE).