Получение отдельных записей из объединенных таблиц, которые могут создавать несколько записей - PullRequest
2 голосов
/ 04 марта 2009

У меня есть ученический стол и регистрационный стол; у студента может быть несколько записей о зачислении, которые могут быть активными или неактивными.

Я хочу получить выбор, который имеет одну запись студента и индикатор того, есть ли у этого студента активные зачисления.

Я думал о том, чтобы сделать это во встроенной пользовательской функции, которая использует идентификатор студента в соединении с таблицей регистрации, но мне интересно, есть ли лучший способ сделать это в одном операторе выбора.

Вызов UDF может выглядеть примерно так:

Select Student_Name,Student_Email,isEnrolled(Student_ID) from Student

Как может выглядеть альтернатива - с одним оператором SQL?

Ответы [ 5 ]

1 голос
/ 04 марта 2009
select  Student_Name,
        Student_Email,
        (select count(*) 
         from Enrollment e 
         where e.student_id = s.student_id
        ) Number_Of_Enrollments 
 from Student e

получит количество зачислений, которое должно помочь.

1 голос
/ 04 марта 2009

Почему бы не присоединиться к дополнительному выбору? В отличие от других решений, это не запускает подзапрос для каждой возвращаемой строки, но собирает данные регистрации для всех сразу. Синтаксис может быть не совсем правильным, но вы должны понять.

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

Edit:
Ренз де Вааль исправил мой плохой SQL!

0 голосов
/ 04 марта 2009
  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

Конечно, замените декодирование функцией, которую использует ваша база данных (или оператором case).

0 голосов
/ 04 марта 2009

старайтесь избегать использования udfs или подзапросов, они снижают производительность. banjolity, кажется, имеет хорошее решение в противном случае, потому что он использует производную таблицу вместо UDF или подвыбора.

0 голосов
/ 04 марта 2009

Попробуйте что-то вроде этого:

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

Я думаю, что вы можете также использовать оператор существует в select, но не положительный

...