Прямо к сути. У меня три таблицы POSTS, TAGS, POST_TAGS
POSTS { p_id, title }
TAGS { t_id, name }
POST_TAGS { p_id, t_id }
Одна почта может иметь несколько тегов, и я хочу выбрать все сообщения, у которых нет определенного тега. например, возьмите эти демо-данные:
TASKS
p_id | title
1 MyPost 1
2 MyPost 2
3 MyPost 3
TAGS
t_id | name
1 red
2 green
POST_TAGS
p_id | t_id
1 1
2 1
2 2
3 2
Теперь я хочу видеть все POSTS, у которых нет TAG 'green'. Мой текущий запрос SQL выглядит так:
SELECT DISCTINCT
p.p_id, p.title
FROM
POSTS as p,
POST_TAGS as pt
WHERE
pt.p_id = p.p_id AND pt.t_id != 2
но это вернет мне это
RESULT
p_id | title
1 MyPost 1
2 MyPost 2
потому что "MyPost 2" также имеет красный цвет TAG, это список.
Желаемый результат:
RESULT
p_id | title
1 MyPost 1
EDIT: Спасибо всем вам, ребята, я принял GarethD ответ, потому что NOT EXISTS более понятен. NOT IN работает, но не сохраняет NULL (даже если я не просил об этом - благодаря Нико Хаазе)
Решение GermanC также корректно и работает, но не так понятно, как выбранный ответ. и тебе спасибо.
Вы можете сделать это, используя NOT EXISTS
:
SELECT p.p_id, p.title
FROM POSTS AS p
WHERE NOT EXISTS
( SELECT 1
FROM POST_TAGS AS pt
WHERE pt.p_id = p.p_id
AND pt.t_id = 2
);
Вы можете явно присоединиться к поиску Зеленого тега и показать те сообщения, в которых соединение не было успешным:
SELECT
p.p_id, p.title
FROM
POSTS as p
LEFT OUTER JOIN
POST_TAGS as pt on pt.p_id = p.p_id AND pt.t_id = 2
WHERE
pt.p_id is null
Это выполнит задание, поскольку оно ищет все сообщения, помеченные 2 во внутреннем запросе и исключающие их во внешнем
SELECT DISTINCT p.p_id WHERE p.p_id NOT IN(
SELECT DISCTINCT
p.p_id
FROM
POSTS as p,
POST_TAGS as pt
WHERE
pt.p_id = p.p_id AND pt.t_id = 2
)