Mysql пустое соединение таблицы не удается - PullRequest
0 голосов
/ 05 мая 2018

Справочная информация, у меня есть задание cron, которое запрашивает ключевые слова, связанные с сообщениями. Если это ключевое слово найдено, пользователь получает сообщение по электронной почте.

Задание cron запускается каждую минуту, поэтому, как только пользователь получит электронное письмо, уведомление больше не будет появляться Следующий запрос выполняется:

SELECT DISTINCT p.id AS post_id, u.display_name, u.id AS user_id, u.email, k.keyword, k.id AS keyword_id
FROM posts p, user_subscriptions us, keywords_users ku, keywords k, users u
LEFT JOIN keyword_subscription_sent kss ON kss.user_id = u.id
LEFT JOIN keywords_posts kp ON kss.post_id = kp.post_id
WHERE us.keywords = 1
AND ku.user_id = u.id
AND ku.keyword_id = k.id
AND kp.keyword_id = k.id
#AND kss.user_id IS NULL AND kss.post_id IS NULL
LIMIT 0, 200

Запрос работает, как и ожидалось, при заполнении таблицы keys_posts kp.

Если таблица keys_posts kp пуста, запрос никогда ничего не вернет. Я попытался исправить это, добавив в предложение WHERE:

AND kss.user_id IS NULL AND kss.post_id IS NULL

Но добавление этого в предложение WHERE приведет к тому, что запрос никогда не будет вообще ничего возвращать.

Желаемый результат:

Запрос вернет все строки, кроме перечисленных в таблице kpwords_posts.

Ответы [ 3 ]

0 голосов
/ 05 мая 2018

Предложения:

Переместите условия, которые требуют, чтобы столбец отличался от NULL, из предложения WHERE до соответствующего предложения ON внешнего соединения.

Не смешивайте синтаксис запятой старой школы (для операции соединения) с синтаксисом ключевого слова JOIN. Откажитесь от синтаксиса запятой и просто используйте JOIN. И перенесите условия соединения в предложение ON.


Перемещение условия в предложение ON внешнего соединения позволит вернуть значения NULL.

Если мы сделаем это предложение WHERE, обратите внимание, что условие

WHERE ( col = some_non_null_val AND col IS NULL ) 

гарантированно никогда не оценивается как ИСТИНА. (Условие проверяется для каждой отдельной строки.) Будут возвращены только те строки, в которых условие оценивается как ИСТИНА. Скорее всего, вы хотели использовать OR вместо AND.

Но мы можем избежать этого OR, если просто переместим условие

         col = some_non_null_val 

к предложению ON внешнего соединения.


Стесняюсь привести пример запроса в качестве демонстрации. Исходный запрос производит полукартово произведение; например, то, что кажется перекрестным соединением между users и user_subscriptions ... единственным критерием для соответствия user_subscriptions является keywords=1. Так что я не понимаю спецификации.

OP сообщает, что запрос возвращает правильный результат, но я подозреваю, что запрос на самом деле не удовлетворяет предполагаемой спецификации. Я подозреваю, что соответствие между users и user_subscriptions должно включать некоторые дополнительные критерии.

Без более точной спецификации, включая примеры данных и пример ожидаемого вывода, я не могу с чистой совестью привести пример SQL для сценария использования OP.

0 голосов
/ 07 мая 2018

Здравствуйте, vveryone и спасибо за ваш вклад.

Сработало следующее:

SELECT * FROM (SELECT u.id as user_id, u.email, u.display_name, k.id as keyword_id, k.keyword, p.id AS post_id, kp.post_id AS kp_post_id, kp.keyword_id AS kp_keyword_id,
ku.user_id AS ku_user_id, ku.keyword_id AS ku_keyword_id
FROM users u, keywords k, posts p, keywords_posts kp, user_subscriptions us, keywords_users ku
WHERE kp.post_id = p.id AND us.keywords = 1 AND kp.keyword_id = k.id AND ku.keyword_id = k.id AND u.id = ku.user_id
GROUP BY kp.post_id, u.id) AS ukp LEFT JOIN keyword_subscription_sent kss ON ukp.user_id = kss.user_id AND kss.post_id = ukp.post_id WHERE kss.post_id IS NULL  
0 голосов
/ 05 мая 2018

я думаю, что kp_keyword_id = k.id из вашего условия WHERE заставляет запрос ничего не возвращать, когда kp пуст, попробуйте вместо этого поместить его в JOIN, чтобы оно выглядело так:

SELECT DISTINCT p.id AS post_id, u.display_name, u.id AS user_id, u.email, k.keyword, k.id AS keyword_id
FROM posts p, user_subscriptions us, keywords_users ku, keywords k, users u
LEFT JOIN keyword_subscription_sent kss ON kss.user_id = u.id
LEFT JOIN keywords_posts kp ON kss.post_id = kp.post_id AND kp.keyword_id = k.id 
WHERE us.keywords = 1
AND ku.user_id = u.id
AND ku.keyword_id = k.id
LIMIT 0, 200
...