Объединение 3 таблиц и сопоставление нулевых записей - PullRequest
0 голосов
/ 11 октября 2019

У меня 3 таблицы, пользователи, новости, просмотренные новости. Я пытаюсь объединить эти 3 таблицы и найти список новостей, которые не просматривал каждый пользователь.

  • TABLE users
    • идентификатор пользователя
    • имя пользователя
    • статус
  • ТАБЛИЦА news
    • newsid
    • title
    • post_time
  • TABLE news_viewed
    • nvid
    • имя пользователя
    • newsid

Ищете список изusers, которые не читали новости (найдено в news_viewed)

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

$_30daysago = strtotime('-30 days');
SELECT * FROM
(
    SELECT users.username, news_id 
    FROM users inner join news_viewed ON
    users.username = news_viewed.username and users.status='active'
    UNION
    SELECT news_viewed.username, post_time 
    FROM news_viewed inner join news ON
    news_viewed.newsid = news.newsid and news.post_time>'$_30daysago'
) as JoinedTable

Мне нужны требуемые результаты, чтобы включить users.username, news.newsid и news.title.

Любая помощь будет оценена, спасибо!

Ответы [ 2 ]

0 голосов
/ 11 октября 2019

Разработка @ ответа GMB

Ваш запрос:

$_30daysago = strtotime('-30 days');
SELECT * FROM
(
    SELECT users.username, news_id 
    FROM users inner join news_viewed ON
    users.username = news_viewed.username and users.status='active'
    UNION
    SELECT news_viewed.username, post_time 
    FROM news_viewed inner join news ON
    news_viewed.newsid = news.newsid and news.post_time>'$_30daysago'
) as JoinedTable

говорит:

получить всех активных пользователей с новостями, которые они прочитали (внутреннийприсоединиться)

SELECT users.username, news_id 
FROM users inner join news_viewed ON
users.username = news_viewed.username and users.status='active'

и добавить все новости тем пользователям, которые их прочитали за последние 30 дней (внутреннее объединение снова)

SELECT news_viewed.username, post_time 
FROM news_viewed inner join news ON
news_viewed.newsid = news.newsid and news.post_time>'$_30daysago'

Это фактически вызывает все кортежи из news_viewed минус те, в которых пользователь не активен, а новый старше 30 дней.

однако, учитывая использование внутреннего соединения, вы приноситемного повторяющихся записей

1.- Результаты первого запроса, где новый менее 30 дней

2.- Результаты второго запроса, где пользователь активен

, поскольку вы используете UNION, а не UNION ALL, вы неявно запрашиваете SELECT DISTINCT, но поля разные (нет смысла отображать newsid, а затем post_time в том же поле) plus, у вас есть опечатка в имени поля, которая не является news_id


Вы должны смотреть на это с другой стороны. Потенциальные комбинации составляют для сценария, где каждый пользователь прочитал каждое новое. Таким образом, вы получаете эту вселенную за основу (количество пользователей, умноженное на количество новостей), а затем

1 - удаляете неактивных пользователей

2 - удаляете новости старше 30 дней

3- удалите кортежи, которые не связаны в таблице news_viewed

SELECT users.username, news.newsid
FROM users
JOIN news 
   ON users.status='active'  -- removes inactive users
   AND news.post_time>'$_30daysago' -- removes older news
LEFT JOIN 
   news_viewed nv USING (username, newsid) 
WHERE nv.nvid IS NULL -- removes unrelated entries
0 голосов
/ 11 октября 2019

Это хорошее место для использования LEFT JOIN antipattern:

SELECT u.username, n.newsid, n.title
FROM users u
INNER JOIN news n ON n.post_time > ?
LEFT JOIN news_viewed nv 
    ON n.newsid = nv.newsid
    AND nv.username = u.username 
WHERE 
    u.status = 'active' 
    AND nv.nvid IS NULL

Этот запрос генерирует декартово произведение пользователей и последних новостей (т. Е. Время публикации превышает параметр, указанный в ?) и возвращает наборы пользователей / новостей, для которых левое объединение на news_viewed не удалось (следовательно, антипаттерн).

Примечание: неясно, какой столбец использовать в объединении;имя столбца news_viewed (username) обычно указывает на то, что оно относится к users(username), тогда как первичный ключ users выглядит как userid. Исправьте названия столбцов или исправьте ваши отношения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...