Многосоставный идентификатор не удалось связать в SQL Server, и это сбило с толку

#sql #sql-server #subquery #inner-join #window-functions

#sql #sql-server #Подзапрос #внутреннее соединение #окно-функции

Вопрос:

У меня есть этот SQL-запрос:

 SELECT 
    stu.sno, sname, cname
FROM
    sc scc,
    (SELECT AVG(sc.grade) AS avg_grade 
     FROM sc 
     GROUP BY sc.cno) AS avg_grades
INNER JOIN 
    course c ON c.cno = scc.cno
INNER JOIN 
    s stu ON stu.sno = scc.sno;
  

И возникает ошибка, что многосоставный идентификатор scc.cno не может быть привязан. Я в замешательстве — кто-нибудь может мне помочь?

Комментарии:

1. Не смешивайте неявный и явный синтаксис соединения

2. Вероятно, вы предполагали SELECT AVG(...) , что подзапрос должен быть частью SELECT , а не FROM .

3. Действительно ли существует таблица с именем s ? Или это должен быть псевдоним? И нет, где вы используете среднее значение в запросе верхнего уровня.

4. sc представляет для выбора курса для студентов, и я хочу выбрать имя stu, оценка которого (сохраненная в таблице sc) в одном или нескольких курсах ниже средней оценки этого курса.

Ответ №1:

Не смешивайте неявные и явные объединения! На самом деле, не используйте неявные объединения: это архаичный синтаксис, который не должен появляться в новом коде.

Запятая в FROM предложении должна (вероятно) быть CROSS JOIN :

 SELECT stu.sno, sname, cname
FROM sc scc
CROSS JOIN (SELECT AVG(sc.grade) AS avg_grade FROM sc GROUP BY sc.cno) AS avg_grades
INNER JOIN course c on c.cno = scc.cno
INNER JOIN s stu on stu.sno = scc.sno;
  

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

Наконец: вы (вероятно) можете использовать оконные функции вместо подзапроса:

 SELECT stu.sno, sname, cname, scc.
FROM (SELECT *, AVG(grade) OVER() avg_grade FROM sc) scc
INNER JOIN course c on c.cno = scc.cno
INNER JOIN s stu on stu.sno = scc.sno;
  

Ответ №2:

Предполагая объединение студентов и курсов по принципу «один ко многим» и объединенную таблицу курсов студентов (т. Е. sc ), Рассмотрим упрощенную агрегацию по объединенным таблицам. Обязательно всегда указывайте столбцы с псевдонимом, если запрос содержит больше, чем в таблице:

 SELECT 
    s.sno AS student_number
    , s.sname AS student_name
    , c.cname AS course_name
    , AVG(sc.grade) AS avg_grade
FROM
    sc
INNER JOIN 
    course c ON c.cno = sc.cno
INNER JOIN 
    stu s ON s.sno = sc.sno
GROUP BY
    s.sno
    , s.sname
    , c.cname