Как получить совпадающие данные из другой таблицы SQL для двух разных столбцов: Inner Join и / или Union?

У меня есть две таблицы в MS Access, которые отслеживают фасилитаторы классов и классы, которые они облегчают. Две таблицы структурированы следующим образом:

tbl_facilitators

facilID -> a unique autonumber to keep track of individual teachers
facilLname -> the Last name of the facilitator
facilFname -> the First name of the facilitator

tbl_facilitatorClasses

classID -> a unique autonumber to keep track of individual classes
className -> the name of the class (science, math, etc)
primeFacil -> the facilID from the first table of a teacher who is primary facilitator
secondFacil -> the facilID  from the first table of another teacher who is backup facilitator

Я не могу понять, как написать Inner Join, который подтягивает результаты в этом формате:

Column 1:  Class Name
Column 2:  Primary Facilitator's Last Name
Column 3:  Primary Facilitator's First Name
Column 4:  Secondary Facilitator's Last Name
Column 5:  Secondary Facilitator's First Name

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

Это мой рабочий Inner Join:

SELECT tbl_facilitatorClasses.className,
    tbl_facilitators.facilLname, tbl_facilitators.facilFname
FROM tbl_facilitatorClasses
INNER JOIN tbl_facilitators
ON tbl_facilitatorClasses.primeFacil = tbl_facilitators.facilID;

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

РЕШЕНИЕ

Благодаря @philipxy я получил следующий запрос, который работал:

SELECT tblCLS.className,
    tblP.facilLname, tblP.facilFname, tblS.facilLname, tblS.facilFname
FROM (tbl_facilitatorClasses AS tblCLS
INNER JOIN tbl_facilitators AS tblP
ON tblCLS.primeFacil=tblP.facilID)
INNER JOIN tbl_facilitators AS tblS
ON tblCLS.secondFacil=tblS.facilID;

При выполнении нескольких внутренних соединений в MS Access необходимо использовать круглые скобки... Как описано в этом другом посте.

3 ответа

Решение

Каждая базовая таблица имеет шаблон оператора, или предикат, параметризованный по именам столбцов, с помощью которого мы помещаем строку или пропускаем ее. Мы можем использовать сокращение для предиката, которое похоже на его объявление SQL.

// facilitator [facilID] is named [facilFname] [facilLname]
facilitator(facilID, facilLname, facilFname)
// class [classID] named [className] has prime [primeFacil] & backup [secondFacil]
class(classID, className, primeFacil, secondFacil)

Вставка строки в предикат дает утверждение, известное как предложение. Строки, которые составляют истинное предложение, входят в таблицу, а строки, которые составляют ложное предложение, не учитываются. (Таким образом, таблица устанавливает предложение каждой существующей строки и НЕ содержит предложение каждой отсутствующей строки.)

// facilitator f1 is named Jane Doe
facilitator(f1, 'Jane', 'Doe')
// class c1 named CSC101 has prime f1 & backup f8
class(c1, 'CSC101', f1, f8)

Но каждое значение выражения таблицы имеет предикат для каждого выражения. SQL разработан так, что если таблицы T а также U удерживайте строки (без дубликатов), где T (...) и U (...) (соответственно), затем:

  • T CROSS JOIN U содержит строки, где T (...) И U (...)
  • T INNER JOIN U ONcondition содержит строки, в которых условие T(...) AND U(...) AND
  • T LEFT JOIN U ONcondition содержит строки где (только для столбцов U1,...)
    T (...) И U (...) И условие
    ИЛИ Т (...)
    И НЕ существует СУЩЕСТВУЮЩИХ значений для U1,... где [U(...) И условие ]
    И U1 НУЛЬ И...
  • T WHEREcondition содержит строки, где T (...) И условие
  • T INTERSECT U содержит строки, где T (...) И U (...)
  • T UNION U содержит строки, где T (...) ИЛИ U (...)
  • T EXCEPT U содержит строки, где T (...) И НЕ U (...)
  • SELECT DISTINCT * FROM T содержит строки, где T (...)
  • SELECT DISTINCTcolumns to keepFROM T содержит строки где
    там СУЩЕСТВУЮТ значения для столбцов, чтобы отбросить где T (...)
  • VALUES (C1, C2, ...)((v1,v2, ...), ...) содержит строки где
    С1 = v1 И С2 = v2 И... ИЛИ...

Также:

  • (...) IN T означает Т (...)
  • scalar= T означает Т (скаляр)
  • T (..., X,...) И X = Y означает T(..., Y, ...) И X = Y

Таким образом, для запроса мы находим способ выражения предиката для строк, которые нам нужны, на естественном языке, используя предикаты базовой таблицы, затем сокращенно с использованием предикатов базовой таблицы, затем в SQL, используя имена базовых таблиц (плюс условия, где это необходимо). Если нам нужно упомянуть таблицу дважды, мы даем ей псевдонимы.

// natural language
there EXISTS values for classID, primeFacil & secondFacil where
    class [classID] named [className] has prime [primeFacil] & backup [secondFacil]
AND facilitator [primeFacil] is named [pf.facilFname] [pf.facilLname]
AND facilitator [secondFacil] is named [sf.facilFname] [sf.facilLname]

// shorthand
there EXISTS values for classID, primeFacil & secondFacil where
    class(classID,className, primeFacil, secondFacil)
AND facilitator(pf.facilID, pf.facilLname, pf.facilFname)
AND pf.facilID = primeFacil
AND facilitator(sf.facilID, sf.facilLname, sf.facilFname)
AND sf.facilID = secondFacil

// table names & (MS Access) SQL
SELECT className, pf.facilLname, pf.facilFname, sf.facilLname, sf.facilFname
FROM (class JOIN facilitator AS pf ON pf.facilID = primeFacil)
JOIN facilitator AS sf ON sf.facilID = secondFacil

OUTER JOIN будет использоваться, когда у класса не всегда есть оба фасилитатора или что-то не всегда имеет все имена. (То есть, если столбец может иметь значение NULL.) Но вы не указали конкретные предикаты для своей базовой таблицы и запроса или бизнес-правила о том, когда все может быть NULL, поэтому я не принял NULL.

(Re MS Access JOIN скобки видят это из SO и это из MS.)

Просто сделайте дополнительное соединение для вспомогательного посредника (и, пожалуйста, используйте псевдонимы таблиц!):

SELECT fc.className, f1.facilLname, f2.facilFname
FROM tbl_facilitatorClasses fc
INNER JOIN tbl_facilitators f1 ON fc.primeFacil = f1.facilID
INNER JOIN tbl_facilitators f2 ON fc.secondFacil = f2.facilID;

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

Другие вопросы по тегам