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

18

Я пытаюсь построить запрос, который будет содержать столбец, указывающий, загрузил ли пользователь документ. У меня есть таблица под названием 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 - есть ли оператор, который даст мне то, что я хочу здесь? Должен ли я придерживаться другого подхода? Или это невозможно?

    
задан ine 20.10.2008 в 18:25
источник

3 ответа

36

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

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

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

    
ответ дан matt b 20.10.2008 в 18:27
источник
  • Отлично! Это то, что я искал. –  ine 20.10.2008 в 18:30
  • EDIT: Ответил на мой собственный вопрос. Я смог найти отличное объяснение, почему это так. weblogs.sqlteam.com/jeffs/archive/2007/05/14/... –  Tyler Forsythe 22.09.2014 в 22:20
4
WHERE HasDownloaded.memberId IS NULL OR HasDownloaded.memberId = @memberId

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

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

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

    
ответ дан Mark Brackett 20.10.2008 в 18:58
источник
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 все-таки немного более эффективно. Интересно! Еще раз, спасибо вам обоим за вашу помощь.

    
ответ дан ine 20.10.2008 в 19:46
источник