仅检索关节具有依赖性的行

Retrieving only rows for which a join has a dependancy

我正在创建一个测试系统,允许用户重新测试直到通过。我想为给定的 UserID 获取分配给他们的测试列表,这些测试的分数低于通过(此示例为 100%)。

我有以下表格:

(Everything here has been adapted for simplicity, but it should all be valid still)

Users
(Generic "users" table with UserID and Name, etc...)

Tests
+--------+----------+------------------+
| TestID | TestName | OtherTestColumns |
+--------+----------+------------------+
|      1 |   Test 1 |         Blah.... |
|      2 |   Test 2 |         Blah.... |
|      3 |   Test 3 |         Blah.... |
|      4 |   Test 4 |         Blah.... |
+--------+----------+------------------+

Users_Have_Tests
  Users are assigned tests they must take with this table
+--------+--------+
| UserID | TestID |
+--------+--------+
|      1 |      1 |
|      1 |      2 |
|      1 |      3 |
|      2 |      1 |
|      2 |      2 |
|      2 |      3 |
+--------+--------+

TestResults
+--------+--------+------------+
| TestID | UserID | Percentage |
+--------+--------+------------+
|      1 |      1 |         75 |
|      1 |      1 |        100 |
|      2 |      1 |         80 |
|      2 |      1 |        100 |
|      1 |      2 |        100 |
|      2 |      2 |         75 |
+--------+--------+------------+

我可以使用以下查询找出分配给用户的所有测试,但我想从该列表中删除他们已通过的测试

SELECT DISTINCT
    TestID,
    TestName
FROM
    `Users` AS u
RIGHT JOIN
    `Users_have_Tests` AS ut
    ON
        u.UserID = ut.UserID
LEFT JOIN
    `Tests` AS t
    ON
        ut.TestID = t.TestID
WHERE UserID = 1

感觉这里需要一个子查询。我想出了以下查询来查找用户参加的每个测试的最高分数,但我不太确定如何将它们联系在一起。 (子查询对我来说很新,我仍在努力理解它们。)

SELECT DISTINCT
    TestID,
    MAX(Percentage)
FROM
    `TestResults`
WHERE UserID = 1
GROUP BY TestID

我要查找的结果是:

UserID = 1
+--------+----------+
| TestID | TestName |
+--------+----------+
|      3 |   Test 3 |
+--------+----------+

UserID = 2
+--------+----------+
| TestID | TestName |
+--------+----------+
|      2 |   Test 2 |
|      3 |   Test 3 |
+--------+----------+

我已经尝试了多种连接和条件方式,但我无法完全理解我在这里到底需要什么。 Google 和 Whosebug 让我失望了;可能是因为我不知道要搜索什么。

编辑 以下是对我有用的:

SELECT DISTINCT t.TestID, t.TestName
    FROM 'Users' AS u
    RIGHT JOIN 'Users_have_Tests' AS ut
        ON u.UserID = ut.UserID
    LEFT JOIN 'Tests' AS t
        ON ut.TestID = t.TestID
    WHERE t.TestID NOT IN (
        SELECT tr.TestID
            FROM TestResults AS tr
            WHERE tr.Percentage >= 100
            AND tr.UserID = 2
        )
    AND u.UserID = 2

我可能遗漏了一些东西,但为什么不直接 运行 以下查询并处理结果呢?

    SELECT ut.UserId, ut.TestId, t.TestName
    FROM `Users_Have_Tests` ut INNER JOIN `TestResults` r ON ut.TestId = r.TestId
      INNER JOIN `Tests` t ON t.TestId = r.TestId
    WHERE r.Percentage < 100
    ORDER BY ut.UserId, ut.TestId;

如果您计划为单个用户执行此操作,只需添加 WHERE 子句条目以针对单个 UserId 值进行过滤。

您尝试过以下方法吗?

编辑我注意到你想看到最高分,所以我创建了一个子查询

编辑我忘了分组。

此外,Test 需要同时加入 TestID 和 UserID。

        SELECT
            TestID,
            TestName,
            HighestScore
        FROM
            `Users` AS u
        RIGHT JOIN
            `Users_have_Tests` AS ut
            ON
                u.UserID = ut.UserID
        LEFT JOIN
        (   SELECT TestID, UserID, MAX(Percentage) AS HighestScore
            FROM `Tests`
            GROUP BY TestID, UserID         
        )AS t
            ON
                ut.TestID = t.TestID
            AND ut.UserID = t.UserID
        WHERE HighestScore < 100
        GROUP BY TestID, TestName, HighestScore

试试 having 子句

调用后

MAX(百分比)AS HighestScore

分组后

拥有 Highest_Score < 100

然后将 100 替换为最低及格分数。只有没有超过及格分数的测试才会被返回。

http://dev.mysql.com/doc/refman/5.0/en/group-by-handling.html

我想我明白你现在想要什么了,试试看吧:

SELECT DISTINCT
        TestID,
        TestName
    FROM
        `Users` AS u
    RIGHT JOIN
        `Users_have_Tests` AS ut
        ON
            u.UserID = ut.UserID
    LEFT JOIN
        `Tests` AS t
        ON
            ut.TestID = t.TestID
    WHERE TestID NOT IN (SELECT TestID
                         FROM TestResults
                         Where Percentage = 100)
    GROUP BY UserID