Reputation: 82
I am making a notifications table. That is structured like this:
notifications:
+----+------+----------------------+-----------------------------------+-----------+
| ID | user | notification | message | timestamp |
+----+------+----------------------+-----------------------------------+-----------+
| 1 | 6 | Denied acceptance | You have been denied for... | |
| 2 | 6 | Apreooved acceptance | You have been accepted... | |
| 3 | 0 | Open slots | there are still open slots for... | |
+----+------+----------------------+-----------------------------------+-----------+
And a table that indicates which notification was read by each user
notifications_read
+----+------+--------------+-----------+
| ID | user | notification | timestamp |
+----+------+--------------+-----------+
| 1 | 6 | 2 | |
+----+------+--------------+-----------+
If notification is meant only for one user, there is a user id under "user" in "notifications"- If the notification is meant for everybody I insert '0' under user.
I am trying to make a query that selects rows from "notifications", that is not read.
My current query is not ok:
SELECT *
FROM notifications
WHERE id NOT IN
(SELECT notification
FROM notification_read
WHERE user = $id) AND user = $id OR user = 0
So for above table it needs to select the rows with id 1 & 3
Thank you for the help!
Upvotes: 0
Views: 507
Reputation: 1951
SELECT n.*
FROM notifications n
LEFT JOIN notifications_read nr ON nr.notification = n.id
WHERE
nr.id IS NULL
This will give you notifications that don't exist n the notifications_read table.
Left join will give you all rows in notifications and join rows from notifications_read that have a notification id. So when you filter by nr.id IS NULL
you will return rows that exist in notifications
but not in notifications_read
.
Additionally, the LEFT JOIN will perform better.
A LEFT [OUTER] JOIN can be faster than an equivalent subquery because the server might be able to optimize it better—a fact that is not specific to MySQL Server alone. https://dev.mysql.com/doc/refman/5.7/en/rewriting-subqueries.html
Upvotes: 1
Reputation: 1270693
If you want unread notifications for a particular user, then you are on the right track:
SELECT n.*
FROM notifications n
WHERE n.id NOT IN (SELECT nr.notification
FROM notification_read nr
WHERE nr.user = $id) AND
(n.user = $id OR n.user = 0);
I think the only issue is the parentheses for the logic around OR
.
You can also write this using IN
:
SELECT n.*
FROM notifications n
WHERE n.id NOT IN (SELECT nr.notification
FROM notification_read nr
WHERE nr.user = $id) AND
n.user IN (0, $id);
Upvotes: 1