Как отфильтровать пользователей по объединенной таблице, в которой значения для поля «заблокировано» будут равны 1, 0 или NULL - PullRequest
1 голос
/ 18 марта 2011

В настоящее время у меня есть две таблицы:

Пользователи

id,

и т. Д.

Соединения

user_id_1

user_id_2

заблокирован

*, где user_id_1 - следующий пользователь, а user_id_2 - пользователь-последователь (в моделиTwitter) *


В настоящее время я изменяю свою внутреннюю систему обмена сообщениями, чтобы позволить всем пользователям отправлять сообщения всем другим пользователям, с единственным ограничением, что если пользователь A отправляет сообщения пользователю B, но пользователь B заблокировал пользователяА, сообщение не пройдет.

Имея это в виду, взгляните на этот запрос:

SELECT u.id, IFNULL(c.blocked, 0) AS blocked
FROM cms_users u
    LEFT JOIN cms_connections c ON u.id=c.user_id_2 AND c.user_id_1=71
WHERE u.id IN (62, 65, 89, 90)

Идея в том, что пользователь 71 пытается отправить сообщение пользователям 62,65, 89 и 90. Пользователь 71 следует 62, 65 и 89, но не следует 90. Однако пользователь 89 заблокировал пользователя 71. Это означает, что в таблице соединений есть записи, которые выглядят следующим образом:

user_id_1       user_id_2       blocked
71              62              0
71              65              0
71              89              1

Когда я запускаю этот запрос, я получаю следующий результат:

user_id_1       blocked
62              0
65              0
89              1
90              0

Это именно то, что я ожидаю,однако, если я изменю предложение WHERE, чтобы оно выглядело так:

WHERE u.id IN (62, 65, 89, 90) AND blocked=0

Тогда я получу это:

user_id_1       blocked
62              0
65              0

Это сбивает с толку меня, потому что я ожидаю три строки: двавыше и один для пользователя 90. Я также попытался сделать GROUP BY с HAVING blocked!=1 и HAVING blocked=0, и все они дают одинаковый результат.Я также попытался изменить имя созданного столбца на block или herpderp, просто чтобы проверить, не был ли конфликт с моим JOIN, но это дало тот же результат.

Любопытно посмотреть, что выребята могут придумать: -)

Ответы [ 2 ]

3 голосов
/ 18 марта 2011

Изменить на IFNULL(c.blocked, 0)

SELECT u.id, 
       Ifnull(c.blocked, 0) AS blocked 
FROM   cms_users u 
       LEFT JOIN cms_connections c 
         ON u.id = c.user_id_2 
            AND c.user_id_1 = 71 
WHERE  u.id IN ( 62, 65, 89, 90 ) 
       AND Ifnull(c.blocked, 0) = 0 

Этот запрос можно улучшить, если переписать в

SELECT u.id, 
       Ifnull(c.blocked, 0) AS blocked 
FROM   cms_users u 
       LEFT JOIN cms_connections c 
         ON c.user_id_1 = 71  
            AND u.id = c.user_id_2 
       JOIN (SELECT 62 AS uu 
             UNION ALL 
             SELECT 65 AS uu 
             UNION ALL 
             SELECT 89 AS uu 
             UNION ALL 
             SELECT 90 AS uu) d 
         ON u.id = d.uu 
WHERE  Ifnull(c.blocked, 0) = 0 

Вам нужны индексы на

  • (cms_users.id)
  • (cms_connections.user_id_1, cms_connections.user_id_2, cms_connections.user_id_2.blocked)
1 голос
/ 18 марта 2011

Попробуйте: ИМЕТЬ IFNULL (заблокирован, 0) = 0

...