2010-11-17 5 views
1

Я пытаюсь сделать довольно сложный (для меня, по крайней мере) запрос, который включает в себя выборку строк, которые могут иметь значения NULL.MySQL JOINs с NULL значениями

Здесь четыре стола, tags, questions_tags, users_experience и answers. Соединения довольно просты. Вопросы отмечены, теги имеют имена, пользователи дают ответы на вопросы, а пользователи имеют опыт работы с определенными тегами. Я хочу найти ответы, которые дали пользователи, и их опыт (который может быть NULL) для тегов вопросов. Я заказываю по количеству ответов, заданных для определенного тега.

Мой запрос заключается в следующем. Это вовсе не оптимизированы (а если у вас есть предложения по оптимизации, пожалуйста, предложите прочь!):

SELECT t.tag_id, t.name, ue.body, COUNT(a.qid) 
FROM tags AS t 
LEFT JOIN users_experience AS ue 
    ON t.tag_id = ue.tag_id 
LEFT JOIN questions_tags AS qt 
    ON qt.tag_id = t.tag_id 
LEFT JOIN answers AS a 
    ON a.qid = qt.qid 
WHERE a.uid=1 
GROUP BY t.tag_id 
ORDER BY COUNT(a.qid) DESC; 

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

Я попытался добавить AND ue.uid = 1 к запросу, но это ограничит результаты только теми, где опыт уже предоставлен, и не возвращать значения NULL, которые я желаю.

Любые мысли о том, что делать?

ответ

2

Ваш AND ue.uid = 1 инстинкт не был неправ, но она принадлежит в пункте ON поэтому часть JOIN, и он используется, чтобы определить, какие строки имеют право присоединиться.

LEFT JOIN users_experience AS ue 
    ON t.tag_id = ue.tag_id AND ue.uid = a.uid 

(И присоединиться должны быть помещены под answers присоединиться.)

+0

Awesome, спасибо! –

0

Я думаю, вам нужно включить таблицу пользователя. Фильтр по uid в таблице пользователя (где это гарантировано), и это должно дать вам то, что вы хотите. (включая нулевые значения). Я не знаю точно, что ваша пользовательская таблица выглядит, но я предполагаю, что ваш запрос будет что-то вроде этого:

SELECT t.tag_id, t.name, ue.body, COUNT(a.qid) 
    FROM users 
LEFT JOIN users_experience AS ue 
    ON users.uid = ue.uid 
LEFT JOIN tags 
    ON t.tag_id = ue.tag_id 
LEFT JOIN questions_tags AS qt 
    ON qt.tag_id = t.tag_id 
LEFT JOIN answers AS a 
    ON a.qid = qt.qid 
WHERE users.uid=1 
GROUP BY t.tag_id 
ORDER BY COUNT(a.qid) DESC; 

Что касается оптимизации - LEFT JOIN обычно считается плохим, если эти таблицы довольно малы. MySQL в основном должен искать всю таблицу для значений NULL. Возможно, на самом деле было бы быстрее проверить, есть ли у пользователя какие-либо записи в левых связанных таблицах и только второй запрос, используя обычный JOIN, только если вы найдете записи.

Надеюсь, что это поможет!

+0

Вы больше не присоединиться к 'users_experience' на соответствующих тегов; вы считаете весь опыт во всех областях. И нет необходимости присоединяться к «пользователям», если значение 'uid' уже доступно (это просто добавляет ненужную обработку). – VoteyDisciple

+0

@VoteyDisciple - он хочет информацию пользователя, где у них есть опыт или нет. Его первоначальная проблема заключалась в том, что когда он добавляет идентификатор пользователя, он не получает значений NULL. Это связано с тем, что идентификатор пользователя является нулевым в его таблице user_experience. Я добавил теги на user_experience в обратном порядке. Он по-прежнему работает. (Заметьте, я не думаю, что это хорошая идея, я думаю, он должен пересмотреть дизайн своего стола) – Cfreak