【发布时间】:2017-11-06 00:44:08
【问题描述】:
更新为公关。下方 cmets 中的@philipxy 建议
(感谢输入)
我在 MySQL 数据库中有 2 个表,结构如下
论坛主题
| id | date | dateEdit | userID | title | summary | randomString |
--------------------------------------------------------------------------
| 1 | <date> | <date> | 1 | Welcome | Welcome | jhdsa76dfasi |
| | | | | | message | |
--------------------------------------------------------------------------
| 2 | <date> | <date> | 5 | LEFT | How to | oiasud88ashk |
| | | | | JOIN | LEFT JOIN | |
--------------------------------------------------------------------------
| 3 | <date> | <date> | 6 | Not the | How to do | lkdsajlkjdf7 |
| | | | | right | it right | |
| | | | | way | | |
--------------------------------------------------------------------------
.
.
.
--------------------------------------------------------------------------
| n | <date> | <date> | <user> | title-n | summary-n | randomString-n |
--------------------------------------------------------------------------
(id 为 1 的用户写了 id 为 1 的主题)
(ID 为 5 的用户写了 ID 为 2 的主题)
(ID 为 6 的用户写了 ID 为 3 的主题)
等等
论坛主题视图
-----------------------------
| id | userID | topicID |
-----------------------------
| 1 | 1 | 2 |
-----------------------------
| 2 | 5 | 1 |
-----------------------------
| 3 | 5 | 3 |
-----------------------------
| 4 | 6 | 1 |
-----------------------------
.
.
.
-----------------------------
| n | <userID> | <topicID> |
-----------------------------
(上表中 id 为 1 的用户观看了 id 为 2 的主题)
(上表中 id 为 5 的用户观看了 id 为 1 的主题)
(上表中 id 为 5 的用户观看了 id 为 3 的主题)
(上表中 id 为 6 的用户观看了 id 为 1 的主题)
等等
我要做什么
我正在尝试获取所有主题的信息,这些主题不是由登录用户编写的,也没有被登录用户查看过
所以对于用户 1:
用户 1 写了主题 1 并查看了主题 2
SELECT 语句应该显示所有不是 1 和 2(即 3)的主题的信息
对于用户 5:
用户 5 写了主题 2 并查看了主题 1 和 3
然后 SELECT 语句应该显示所有不是 1、2 和 3 的主题的信息(即没有结果)
对于用户 6:
用户 6 写了主题 3 并查看了主题 1
然后 SELECT 语句应该显示所有不是 1 和 3(即 2)的主题的信息
如何在单个 SELECT 语句中执行此操作?
connection.php
try {
$servername = "localhost";
$username = "******";
$password = "**************";
$database = "*****";
$charset = 'utf8';
$dsn = "mysql:host=$servername;dbname=$database;charset=$charset";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO ( $dsn , $username , $password , $opt );
} catch ( PDOException $e ) {
file_put_contents ( 'PDOError.txt', $e->getMessage(), FILE_APPEND );
echo "Failed to connect to database!";
die ();
}
有效但繁琐的代码:
functions.php
require ( '../scripts/connection.php' );
function getTopic ($pdo) {
// Set userID for user logged in
if ( isset ( $_SESSION['id'] ) ) {
$userID = $_SESSION['id'];
}
try {
// Find all topics not written by user logged in
$prepareTopic = $pdo->prepare( "SELECT id , date , title , summary , randomString FROM forumtopic WHERE userID != ? ORDER BY date DESC" );
$prepareTopic->execute([$userID]);
$getTopic = $prepareTopic->fetchAll();
} catch ( PDOException $e ) {
file_put_contents ( 'error.txt', $e->getMessage(), FILE_APPEND );
}
// If found topics not written by user logged in
if ( $getTopic ) {
foreach ( $getTopic as $row ) {
// Set topicID and use it to see if user logged in has already viewed it
$topicID = $row['id'];
try {
// Find if specific topic viewed by user logged in
$prepareTopicview = $pdo->prepare( "SELECT id FROM forumtopicview WHERE ( userID = ? AND topicID = ? ) LIMIT 1" );
$prepareTopicview->execute([$userID,$topicID]);
$getTopicView = $prepareTopicview->fetch();
} catch ( PDOException $e ) {
file_put_contents ( 'error.txt', $e->getMessage(), FILE_APPEND );
}
// Only if specific topic not viewed by user logged in
if ( !$getTopicView ) {
// Set needed variables
$dateTopic[] = $row['date'];
$titleTopic[] = $row['title'];
$summaryTopic[] = $row['summary'];
$randomStringTopic[] = $row['randomString'];
}
}
}
}
但这是很多代码的方式
我想做的事
functions.php
if ( isset ( $_SESSION['id']; ) ) {
$userID = $_SESSION['id'];
}
try {
$prepareTopic = $pdo->( "SELECT..." );
$prepareTopic->execute([$userID]);
$getTopic = $prepareTopic->fetchAll();
} catch ( PDOException $e ) {
file_put_contents ( 'error.txt', $e->getMessage(), FILE_APPEND );
}
if ( $getTopic ) {
foreach ( $getTopic as $row ) {
$dateTopic[] = $row['date'];
$titleTopic[] = $row['title'];
$summaryTopic[] = $row['summary'];
$randomStringTopic[] = $row['randomString'];
}
}
插入单个 SELECT 语句
而且我知道可以在单个 SELECT 语句中完成所有这些操作 - 但我已经退出“游戏”有一段时间了,我似乎无法让它发挥作用
应该按照建议的解决方案工作
SELECT <select_list> FROM forumtopic t LEFT JOIN forumtopicview v ON t.userID = v.userID AND t.id = v.topicID WHERE t.userID <> ? AND v.id IS NULL
它不包括所有由登录用户编写的主题 (t.userID ?)
但不排除已登录用户查看的那些(t.userID = v.userID AND t.id = v.topicID)
希望有人能帮忙
【问题讨论】:
-
顺便说一句:你的 sql 中有一个错误(有 2 个 where 子句)
-
如果您仍想得到答案,请不要接受该问题。或者,如果它导致您更改问题,请发布新问题。另外,请不要添加“编辑”,编辑您的问题,以使其成为您所问问题的最佳措辞。另请阅读minimal reproducible example 并采取行动。请同时格式化您的代码,以便 SQL 也被格式化。
-
left join返回由inner join执行的行加上由nulls 扩展的不匹配的左表行。on比where绑定得更紧密,但其他方面是相同的。 -
你不清楚。例如,您说建议的答案“有效”,但没有奏效。例如:告诉我们你的查询做了什么代数运算没有什么意义;我们知道它的作用,我们需要知道您认为沿途表格中有哪些行。因此,经过我的一些编辑后,您的规范“[ir] 用户编写的 [not] 主题 [not] 和 [ir] 用户 [不] 查看的 [forumtopic rows]”很有帮助。 1“[ir] 用户未编写的 [forumtopic rows] 主题”相同。但 2 和 3 不清楚。根据基本关系中的哪些行或到目前为止的行,告诉我们您想要/期望哪些行。
-
PS 你不知道你的基表中的行说什么。除非您这样做,否则没有人可以使用数据库。 forumtopic 中的一行关于它的 id、userID 等说明了什么。目前尚不清楚您所说的“不是由用户编写的主题”是什么意思。