MySQL СОЕДИНЯЕТСЯ со значениями NULL - PullRequest
2 голосов
/ 18 ноября 2010

Я пытаюсь сделать довольно сложный (по крайней мере для меня) запрос, который включает выборку строк, которые могут иметь значения 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 ]

2 голосов
/ 18 ноября 2010

Ваш инстинкт 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 голосов
/ 18 ноября 2010

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

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, только если вы найдете записи.

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

...