Помощь с WHERE в LEFT JOIN SQL Query

Я пытаюсь построить запрос, который будет содержать столбец, указывающий, загрузил ли пользователь документ. У меня есть таблица под названием HasDownloaded со следующими столбцами: id, documentID, memberID. Узнать, загружен ли пользователь конкретный документ, легко; но мне нужно сгенерировать запрос, в котором результаты будут выглядеть следующим образом:

name              id
----------------------
abc               NULL
bbb               2
ccc               53
ddd               NULL
eee               13

Идентификатор не очень важен; меня интересует, был ли загружен документ (это NULL или нет).

Вот мой запрос:

SELECT Documents.name, HasDownloaded.id FROM Documents
LEFT JOIN HasDownloaded ON HasDownloaded.documentID = Documents.id
WHERE HasDownloaded.memberID = @memberID

Проблема заключается в том, что это приведет только к возврату значений, если для указанного пользователя существует запись в таблице HasDownloaded. Я хотел бы сохранить это просто и только иметь записи в HasDownloaded для документов, которые были загружены. Поэтому, если пользователь 1 загрузил abc, bbb и ccc, я все равно хочу, чтобы ddd и eee отображались в результирующей таблице, только с идентификатором как NULL. Но предложение WHERE дает только значения, для которых существуют записи.

Я не очень эксперт по SQL - есть ли оператор, который даст мне то, что я хочу здесь? Должен ли я придерживаться другого подхода? Или это невозможно?

Ответы

Ответ 1

Переместить условие в предложении WHERE в условие соединения.

SELECT Documents.name, HasDownloaded.id FROM Documents
LEFT JOIN HasDownloaded ON HasDownloaded.documentID = Documents.id 
  AND HasDownloaded.memberID = @memberID 

Это необходимо, когда вы хотите обратиться к левой таблице join-ed в том, что в противном случае было бы предложением WHERE.

Ответ 2

WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId

был бы нормальным способом сделать это. Некоторые сократили бы его до:

WHERE COALESCE(HasDownloaded.memberId, @memberId) = @memberId

Вы можете, как показывает Мэтт Б., сделать это в своем JOIN состоянии, но я думаю, что гораздо больше шансов запутать людей. Если вы не понимаете, ПОЧЕМУ переместить его в предложение JOIN, то я настоятельно рекомендую держаться подальше от него.

Ответ 3

@Mark: Я понимаю, почему работает синтаксис JOIN, но спасибо за предупреждение. Я думаю, ваше предложение более интуитивное. Мне было любопытно узнать, какая из них была более эффективной. Поэтому я провел быстрый тест (это было довольно просто, я боюсь, всего за 14 строк и 10 проб):

В состоянии JOIN:

AND HasDownloaded.memberID = @memberID
  • Время обработки клиента: 4.6
  • Общее время выполнения: 35,5
  • Время ожидания ответов сервера: 30.9

В предложении WHERE:

WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId
  • Время обработки клиента: 7.7
  • Общее время выполнения: 27.7
  • Время ожидания ответов сервера: 22.0

Похоже, предложение WHERE все-таки немного более эффективно. Интересно! Еще раз, спасибо вам обоим за вашу помощь.