Ripristino di record singoli da tabelle unite che possono produrre più record
-
03-07-2019 - |
Domanda
Ho una tabella degli studenti e una tabella delle iscrizioni; uno studente potrebbe avere più record di iscrizione che possono essere attivi o inattivi.
Voglio ottenere una selezione con un singolo record di studente e un indicatore del fatto che quello studente abbia iscrizioni attive.
Ho pensato di farlo in un UDF in linea che utilizza l'ID studente in un join alla tabella di iscrizione, ma mi chiedo se esiste un modo migliore per farlo in una singola istruzione select.
La chiamata UDF potrebbe assomigliare a:
Select Student_Name,Student_Email,isEnrolled(Student_ID) from Student
Come potrebbe essere l'alternativa - con un'istruzione SQL -?
Soluzione
select Student_Name,
Student_Email,
(select count(*)
from Enrollment e
where e.student_id = s.student_id
) Number_Of_Enrollments
from Student e
otterrà il numero di iscrizioni, il che dovrebbe aiutare.
Altri suggerimenti
Perché non partecipare a una selezione secondaria? A differenza di altre soluzioni, questo non genera una sottoquery per ogni riga restituita, ma raccoglie i dati di iscrizione per tutti contemporaneamente. La sintassi potrebbe non essere del tutto corretta, ma dovresti avere l'idea.
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
La selezione dalle iscrizioni potrebbe anche essere ripetuta come funzione che restituisce una tabella su cui partecipare.
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
Modifica
Renze de Waal ha corretto il mio cattivo SQL!
Prova qualcosa del genere:
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
Penso che tu possa anche usare l'istruzione esistente nella selezione ma non positiva
cerca di evitare di usare udfs o subquery, sono dei killer delle prestazioni. banjolity sembra avere una buona soluzione altrimenti perché usa una tabella derivd invece di un UDF o sottoseleziona.
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
Naturalmente, sostituisci la decodifica con una funzione utilizzata dal tuo database (o, un'istruzione case).