Reputation: 23
Straight to the point. I have three tables POSTS, TAGS, POST_TAGS
POSTS { p_id, title }
TAGS { t_id, name }
POST_TAGS { p_id, t_id }
One post can have multiple tags and i want to select all post that don't have a specific tag. for example take this demo data:
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
Now i want to see all POSTS that do not have the TAG 'green'. My current SQL query looks like this:
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
but this is going to return me this
RESULT
p_id | title
1 MyPost 1
2 MyPost 2
because 'MyPost 2' also has the TAG red it is listet.
Desired result is:
RESULT
p_id | title
1 MyPost 1
EDIT: Thanks to all of you guys, i accepted GarethD answer because NOT EXISTS is more self-explanatory. NOT IN is working but not NULL save (even if i wasn't asking for it - thanks to Nico Haase as well)
GermanC solution also is correct and working, but isn't as self-explanatory as the selected answer. thanks to you too.
Upvotes: 1
Views: 531
Reputation: 69819
You can do this using 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
);
Upvotes: 4
Reputation: 12130
This will do the job, as it searches for all postings which are tagged with 2 in an inner query and excludes them in the outer one
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
)
Upvotes: 0
Reputation: 279
You can explicitely join looking for the Green tag, and show those posts where the join was not successful:
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
Upvotes: 3