从一个 table 中获取不在另一个 table MySQL 中的所有数据
Get all data from one table that's not in another table MySQL
我有一条消息table:
mysql> describe messages;
+-----------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+-------------------+-----------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user1_id | int(11) | NO | | NULL | |
| user1 | varchar(255) | NO | | NULL | |
| user2_id | int(11) | NO | | NULL | |
| user2 | varchar(255) | NO | | NULL | |
| message | text | YES | | NULL | |
| timestamp | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| user1read | varchar(3) | NO | | NULL | |
| user2read | varchar(3) | NO | | NULL | |
+-----------+--------------+------+-----+-------------------+-----------------------------+
9 rows in set (0.00 sec)
然后我有一个被阻止的 table:
mysql> describe blocked;
+-----------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------+------+-----+---------+-------+
| user_id | int(11) | NO | PRI | NULL | |
| blocked_user_id | int(11) | NO | PRI | NULL | |
+-----------------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)
我想要做的是让所有数据显示在页面上的单独 div 中。该脚本每秒调用一次。我最终得到的查询产生了所有消息,无论阻塞状态如何。
所以,假设我的 ID 是 1,而被阻止的用户的 ID 是 5,则用户 5 不应出现在列表中。其他用户登录后也是如此。
在处理该查询一段时间后,我尝试了第二次查询。更糟糕的是,尽管使用相同查询通过手动 SQL 条目返回数据,但页面上 什么都没有 出现。
文件很小,所以我只 post 整个文件:
编辑: 第一个查询实际上是显示所有消息,包括我自己作为消息,这显然是错误的。看来我的查询比我想象的更糟糕。
<?php
session_start();
include '../../../config/DB.php';
$username = $_SESSION['logged_in']; //to use in queries
try {
$db = new DB(); //new DB object
} catch (Exception $e) {
$e->getMessage();
}
try {
$names = array(); //to store during foreach iterations
//get the id for the other query attempt
$id_result = $db->getRow('SELECT id FROM users WHERE username=?', [$username]);
$id = $id_result['id'];
foreach ($messages_result = $db->getRows('SELECT messages.user1, messages.user2, messages.timestamp, messages.message, messages.user2read, users.avatar
FROM messages
LEFT JOIN users ON messages.user1 = users.username
WHERE messages.user2 = ? AND
(users.id NOT IN (SELECT user_id FROM blocked))
OR (users.id NOT IN (SELECT blocked_user_id FROM blocked))
ORDER BY timestamp DESC', [$username]) as $result) {
$sender = $result['user1'];
$time = $result['timestamp'];
$message = $result['message'];
$avatar = $result['avatar'];
$user2read = $result['user2read'];
//Do this so users will only show once.
//One div per user, and when clicked
//all messages are shown elsewhere on a page.
if (!in_array($sender, $names)) {
$names[] = $sender;
//If the message is unread, show name in bold
//Else show regular text
//$avatar has been removed from the html for now
//It shows up in an <img> tag
if ($user2read === 'no') {
echo '<div id="single_message" data-sender="' . $sender . '"><p style="padding-left:8px;"><p><a class="link" style="font-weight:bold;font-size:16px;" href=' . $sender . '>' . $sender . '</a></strong></p><p style="white-space:pre-wrap;margin-left:8px;margin-right:8px;">' . $message . '</p><p style="padding-left:8px;border-bottom: 1px solid #ccc;">' . $time . '</p></div>';
} else {
echo '<div id="single_message" data-sender="' . $sender . '"><p style="padding-left:8px;"><p><a class="link" href=' . $sender . '>' . $sender . '</a></p><p style="white-space:pre-wrap;margin-left:8px;margin-right:8px;">' . $message . '</p><p style="padding-left:8px;border-bottom: 1px solid #ccc;">' . $time . '</p></div>';
}
} else {
continue;
}
}
} catch (Exception $e) {
}
这是我尝试的第二个查询(我将只显示 foreach)。这是页面上没有显示任何内容的那个。
foreach($messages_result = $db->getRows('SELECT * FROM messages m LEFT JOIN blocked b ON ((m.user1_id = b.user_id OR m.user2_id = b.user_id)
AND (m.user1_id = b.blocked_user_id OR m.user2_id = b.blocked_user_id))
WHERE (m.user1_id = 1 OR m.user2_id = 1) HAVING m.user_id IS NULL
ORDER BY timestamp DESC', [$id]) as $result) {
我是不是漏掉了什么?
WHERE (m.user1_id = 1 OR m.user2_id = 1) HAVING m.user_id IS NULL
我认为它相互矛盾,因为你在加入时有这个 ON ((m.user1_id = b.user_id OR m.user2_id = b.user_id) AND (m.user1_id = b.blocked_user_id OR m.user2_id = b.blocked_user_id))
..它就像相互抵消......
改正这个....也许可以....祝你好运
对被阻止的用户进行左连接,将 user2
("me")与 blocked.user_id
、阻止的人以及 user1
与 blocked.blocked_user_id
匹配被阻止的用户,如果结果为 NULL(又名 b.user_id IS NULL),则没有阻止。
foreach($messages_result = $db->getRows('
SELECT messages.user1, messages.user2, messages.timestamp, messages.message, messages.user2read, users.avatar
FROM messages
LEFT JOIN users ON messages.user1 = users.username
LEFT JOIN blocked b ON b.user_id = messages.user2_id AND b.blocked_user_id = messages.user1_id
WHERE messages.user2 = ? AND b.user_id IS NULL
ORDER BY timestamp DESC',[$username]) as $result) {
...
我有一个类似的脚本,它从未被阻止的用户 table 获取所有用户,而不是从消息 table 获取数据。因为这只比较了用户 ID 和被阻止的 ID,所以我可以用一个查询块来完成。但是,我需要检查消息中 user1_id 和 user2_id 之间的所有可能性,以及被阻止的 user_id 和 blocked_user_id 之间的所有可能性。这需要一个额外的块,它是第一个块的反向版本。
我将通过显示来自用户的 ID 和用户名,然后是来自被阻止 table 的每个人,然后是使用被阻止 table 中的 ID 的结果来展示这是如何成功的。
mysql> select id, username from users;
+----+-----------------+
| id | username |
+----+-----------------+
| 1 | csheridan |
| 2 | testuser |
| 3 | testuser2 |
| 4 | washington_user |
+----+-----------------+
4 rows in set (0.00 sec)
mysql> select * from blocked;
+---------+-----------------+
| user_id | blocked_user_id |
+---------+-----------------+
| 1 | 2 |
| 1 | 4 |
+---------+-----------------+
2 rows in set (0.00 sec)
mysql> SELECT m.* FROM messages m
WHERE NOT EXISTS (SELECT 1 FROM blocked b
WHERE b.user_id = m.user1_id AND b.blocked_user_id = 1)
AND NOT EXISTS
(SELECT 1 FROM blocked b WHERE b.blocked_user_id = m.user1_id AND b.user_id = 1)
AND NOT EXISTS (SELECT 1 FROM blocked b WHERE b.user_id = m.user2_id AND b.blocked_user_id = 1)
AND NOT EXISTS (SELECT 1 FROM blocked b WHERE b.blocked_user_id = m.user2_id AND b.user_id = 1)
ORDER BY timestamp DESC;
+----+----------+-----------+----------+-----------+----------------+---------------------+-----------+-----------+
| id | user1_id | user1 | user2_id | user2 | message | timestamp | user1read | user2read |
+----+----------+-----------+----------+-----------+----------------+---------------------+-----------+-----------+
| 2 | 3 | testuser2 | 1 | csheridan | Hey! | 2018-11-14 12:12:35 | yes | no |
| 4 | 3 | testuser2 | 1 | csheridan | Are you there? | 2018-11-14 12:12:35 | yes | no |
+----+----------+-----------+----------+-----------+----------------+---------------------+-----------+-----------+
2 rows in set (0.00 sec)
mysql> SELECT m.* FROM messages m
WHERE NOT EXISTS (SELECT 1 FROM blocked b
WHERE b.user_id = m.user1_id AND b.blocked_user_id = 2)
AND NOT EXISTS (SELECT 1 FROM blocked b WHERE b.blocked_user_id = m.user1_id AND b.user_id = 2)
AND NOT EXISTS (SELECT 1 FROM blocked b WHERE b.user_id = m.user2_id AND b.blocked_user_id = 2)
AND NOT EXISTS (SELECT 1 FROM blocked b WHERE b.blocked_user_id = m.user2_id AND b.user_id = 2)
ORDER BY timestamp DESC;
+----+----------+-----------------+----------+----------+---------------------+---------------------+-----------+-----------+
| id | user1_id | user1 | user2_id | user2 | message | timestamp | user1read | user2read |
+----+----------+-----------------+----------+----------+---------------------+---------------------+-----------+-----------+
| 7 | 4 | washington_user | 2 | testuser | Hey man! What's up? | 2018-11-14 14:32:27 | yes | no |
| 8 | 4 | washington_user | 2 | testuser | Hello there. | 2018-11-14 14:32:27 | yes | no |
+----+----------+-----------------+----------+----------+---------------------+---------------------+-----------+-----------+
2 rows in set (0.00 sec)
所以,问题是我在正确的轨道上,我只需要另一个障碍。首先,我检查了 blocked.user_id = messages.user1_id AND blocked.user_id = ?,然后检查了 other 条件 user2_id。除非有人提出更紧凑的查询,否则这就是我所需要的。
如果我只做了第一个块,它不会检查所有条件并仍然返回被阻止的用户,因为它没有检查消息中的 user1_id 和 user2_id。
我有一条消息table:
mysql> describe messages;
+-----------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+-------------------+-----------------------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user1_id | int(11) | NO | | NULL | |
| user1 | varchar(255) | NO | | NULL | |
| user2_id | int(11) | NO | | NULL | |
| user2 | varchar(255) | NO | | NULL | |
| message | text | YES | | NULL | |
| timestamp | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| user1read | varchar(3) | NO | | NULL | |
| user2read | varchar(3) | NO | | NULL | |
+-----------+--------------+------+-----+-------------------+-----------------------------+
9 rows in set (0.00 sec)
然后我有一个被阻止的 table:
mysql> describe blocked;
+-----------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------+------+-----+---------+-------+
| user_id | int(11) | NO | PRI | NULL | |
| blocked_user_id | int(11) | NO | PRI | NULL | |
+-----------------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)
我想要做的是让所有数据显示在页面上的单独 div 中。该脚本每秒调用一次。我最终得到的查询产生了所有消息,无论阻塞状态如何。
所以,假设我的 ID 是 1,而被阻止的用户的 ID 是 5,则用户 5 不应出现在列表中。其他用户登录后也是如此。
在处理该查询一段时间后,我尝试了第二次查询。更糟糕的是,尽管使用相同查询通过手动 SQL 条目返回数据,但页面上 什么都没有 出现。
文件很小,所以我只 post 整个文件:
编辑: 第一个查询实际上是显示所有消息,包括我自己作为消息,这显然是错误的。看来我的查询比我想象的更糟糕。
<?php
session_start();
include '../../../config/DB.php';
$username = $_SESSION['logged_in']; //to use in queries
try {
$db = new DB(); //new DB object
} catch (Exception $e) {
$e->getMessage();
}
try {
$names = array(); //to store during foreach iterations
//get the id for the other query attempt
$id_result = $db->getRow('SELECT id FROM users WHERE username=?', [$username]);
$id = $id_result['id'];
foreach ($messages_result = $db->getRows('SELECT messages.user1, messages.user2, messages.timestamp, messages.message, messages.user2read, users.avatar
FROM messages
LEFT JOIN users ON messages.user1 = users.username
WHERE messages.user2 = ? AND
(users.id NOT IN (SELECT user_id FROM blocked))
OR (users.id NOT IN (SELECT blocked_user_id FROM blocked))
ORDER BY timestamp DESC', [$username]) as $result) {
$sender = $result['user1'];
$time = $result['timestamp'];
$message = $result['message'];
$avatar = $result['avatar'];
$user2read = $result['user2read'];
//Do this so users will only show once.
//One div per user, and when clicked
//all messages are shown elsewhere on a page.
if (!in_array($sender, $names)) {
$names[] = $sender;
//If the message is unread, show name in bold
//Else show regular text
//$avatar has been removed from the html for now
//It shows up in an <img> tag
if ($user2read === 'no') {
echo '<div id="single_message" data-sender="' . $sender . '"><p style="padding-left:8px;"><p><a class="link" style="font-weight:bold;font-size:16px;" href=' . $sender . '>' . $sender . '</a></strong></p><p style="white-space:pre-wrap;margin-left:8px;margin-right:8px;">' . $message . '</p><p style="padding-left:8px;border-bottom: 1px solid #ccc;">' . $time . '</p></div>';
} else {
echo '<div id="single_message" data-sender="' . $sender . '"><p style="padding-left:8px;"><p><a class="link" href=' . $sender . '>' . $sender . '</a></p><p style="white-space:pre-wrap;margin-left:8px;margin-right:8px;">' . $message . '</p><p style="padding-left:8px;border-bottom: 1px solid #ccc;">' . $time . '</p></div>';
}
} else {
continue;
}
}
} catch (Exception $e) {
}
这是我尝试的第二个查询(我将只显示 foreach)。这是页面上没有显示任何内容的那个。
foreach($messages_result = $db->getRows('SELECT * FROM messages m LEFT JOIN blocked b ON ((m.user1_id = b.user_id OR m.user2_id = b.user_id)
AND (m.user1_id = b.blocked_user_id OR m.user2_id = b.blocked_user_id))
WHERE (m.user1_id = 1 OR m.user2_id = 1) HAVING m.user_id IS NULL
ORDER BY timestamp DESC', [$id]) as $result) {
我是不是漏掉了什么?
WHERE (m.user1_id = 1 OR m.user2_id = 1) HAVING m.user_id IS NULL
我认为它相互矛盾,因为你在加入时有这个 ON ((m.user1_id = b.user_id OR m.user2_id = b.user_id) AND (m.user1_id = b.blocked_user_id OR m.user2_id = b.blocked_user_id))
..它就像相互抵消......
改正这个....也许可以....祝你好运
对被阻止的用户进行左连接,将 user2
("me")与 blocked.user_id
、阻止的人以及 user1
与 blocked.blocked_user_id
匹配被阻止的用户,如果结果为 NULL(又名 b.user_id IS NULL),则没有阻止。
foreach($messages_result = $db->getRows('
SELECT messages.user1, messages.user2, messages.timestamp, messages.message, messages.user2read, users.avatar
FROM messages
LEFT JOIN users ON messages.user1 = users.username
LEFT JOIN blocked b ON b.user_id = messages.user2_id AND b.blocked_user_id = messages.user1_id
WHERE messages.user2 = ? AND b.user_id IS NULL
ORDER BY timestamp DESC',[$username]) as $result) {
...
我有一个类似的脚本,它从未被阻止的用户 table 获取所有用户,而不是从消息 table 获取数据。因为这只比较了用户 ID 和被阻止的 ID,所以我可以用一个查询块来完成。但是,我需要检查消息中 user1_id 和 user2_id 之间的所有可能性,以及被阻止的 user_id 和 blocked_user_id 之间的所有可能性。这需要一个额外的块,它是第一个块的反向版本。
我将通过显示来自用户的 ID 和用户名,然后是来自被阻止 table 的每个人,然后是使用被阻止 table 中的 ID 的结果来展示这是如何成功的。
mysql> select id, username from users;
+----+-----------------+
| id | username |
+----+-----------------+
| 1 | csheridan |
| 2 | testuser |
| 3 | testuser2 |
| 4 | washington_user |
+----+-----------------+
4 rows in set (0.00 sec)
mysql> select * from blocked;
+---------+-----------------+
| user_id | blocked_user_id |
+---------+-----------------+
| 1 | 2 |
| 1 | 4 |
+---------+-----------------+
2 rows in set (0.00 sec)
mysql> SELECT m.* FROM messages m
WHERE NOT EXISTS (SELECT 1 FROM blocked b
WHERE b.user_id = m.user1_id AND b.blocked_user_id = 1)
AND NOT EXISTS
(SELECT 1 FROM blocked b WHERE b.blocked_user_id = m.user1_id AND b.user_id = 1)
AND NOT EXISTS (SELECT 1 FROM blocked b WHERE b.user_id = m.user2_id AND b.blocked_user_id = 1)
AND NOT EXISTS (SELECT 1 FROM blocked b WHERE b.blocked_user_id = m.user2_id AND b.user_id = 1)
ORDER BY timestamp DESC;
+----+----------+-----------+----------+-----------+----------------+---------------------+-----------+-----------+
| id | user1_id | user1 | user2_id | user2 | message | timestamp | user1read | user2read |
+----+----------+-----------+----------+-----------+----------------+---------------------+-----------+-----------+
| 2 | 3 | testuser2 | 1 | csheridan | Hey! | 2018-11-14 12:12:35 | yes | no |
| 4 | 3 | testuser2 | 1 | csheridan | Are you there? | 2018-11-14 12:12:35 | yes | no |
+----+----------+-----------+----------+-----------+----------------+---------------------+-----------+-----------+
2 rows in set (0.00 sec)
mysql> SELECT m.* FROM messages m
WHERE NOT EXISTS (SELECT 1 FROM blocked b
WHERE b.user_id = m.user1_id AND b.blocked_user_id = 2)
AND NOT EXISTS (SELECT 1 FROM blocked b WHERE b.blocked_user_id = m.user1_id AND b.user_id = 2)
AND NOT EXISTS (SELECT 1 FROM blocked b WHERE b.user_id = m.user2_id AND b.blocked_user_id = 2)
AND NOT EXISTS (SELECT 1 FROM blocked b WHERE b.blocked_user_id = m.user2_id AND b.user_id = 2)
ORDER BY timestamp DESC;
+----+----------+-----------------+----------+----------+---------------------+---------------------+-----------+-----------+
| id | user1_id | user1 | user2_id | user2 | message | timestamp | user1read | user2read |
+----+----------+-----------------+----------+----------+---------------------+---------------------+-----------+-----------+
| 7 | 4 | washington_user | 2 | testuser | Hey man! What's up? | 2018-11-14 14:32:27 | yes | no |
| 8 | 4 | washington_user | 2 | testuser | Hello there. | 2018-11-14 14:32:27 | yes | no |
+----+----------+-----------------+----------+----------+---------------------+---------------------+-----------+-----------+
2 rows in set (0.00 sec)
所以,问题是我在正确的轨道上,我只需要另一个障碍。首先,我检查了 blocked.user_id = messages.user1_id AND blocked.user_id = ?,然后检查了 other 条件 user2_id。除非有人提出更紧凑的查询,否则这就是我所需要的。 如果我只做了第一个块,它不会检查所有条件并仍然返回被阻止的用户,因为它没有检查消息中的 user1_id 和 user2_id。