尝试简化代码以从2个表中获取结果,不包括表1中的一些表和表2中的一些

时间:2017-11-06 00:44:08

标签: php mysql join left-join

更新为pr。 @philipxy建议在下面的评论中
(感谢输入)

我在MySQL数据库中有2个表,具有以下结构

forumtopic

| 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写了主题)

forumtopicview

-----------------------------
| 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&lt;&gt;?)
但不排除已登录用户查看的内容(t.userID = v.userID AND t.id = v.topicID)

希望有人可以提供帮助

1 个答案:

答案 0 :(得分:2)

所有主题均未由用户撰写且未被用户查看

SELECT
      t.id
    , t.date
    , t.dateEdit
    , t.userID
    , t.title
    , t.summary
    , t.randomString
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

注意:连接表时,在所有列引用中包含表名或表别名变得非常重要。这可以避免由常见列名引起的错误导致的歧义。

修改

SELECT
      t.id
    , t.date
    , t.dateEdit
    , t.userID
    , t.title
    , t.summary
    , t.randomString
FROM forumtopic t
WHERE t.userID <> ? 
AND NOT EXISTS (
        SELECT NULL
        FROM forumtopicview v where t.id = v.topicID
        AND v.userID = ?
        )