运行 MySQL 中的多个查询未使用子查询

Running multiple queries in MySQL without using sub-query

我有两个 table, 一个 table 叫 users

fsname
emailaddress

和第二个 table 用 emailaddressscoredatetime.

调用了 attempts

现在我想做的是先用 datetime 订购 attempts table 然后选择然后加入 attempt table 和 users table 如果他们有相同的 emailaddress 然后选择每个唯一用户的最终尝试。

简而言之,我必须通过加入这些 table 来选择每个用户的最后一次尝试,这是我为实现此目的而生成的查询,

$query = "SELECT 
            distinct users.fsname, users.emailaddress, attempts.score 
            FROM users 
            INNER JOIN attempts 
            ON users.emailaddress = attempts.emailaddress 
            ORDER BY datetime DESC";

此查询首先假设按 datetimeattempts 进行排序,并且仅选择具有不同名字的值,即此处的 fsname

但是当我执行上面的查询时它 returns 结果具有非唯一值 fsname 尽管我使用 DISTINCTfsname.

谁能告诉我为什么 DISTINCT 不能只选择不同的 fsname 吗?

我已经尝试了 DISTINCT fsnameDISTINCT(fsname),但其中 none 有效。

它没有像您认为的那样工作,documentation 解释了 DISTINCT 的含义:它是关于不同的 :

The ALL and DISTINCT options specify whether duplicate rows should be returned. ALL (the default) specifies that all matching rows should be returned, including duplicates. DISTINCT specifies removal of duplicate rows from the result set. It is an error to specify both options. DISTINCTROW is a synonym for DISTINCT.

(来源:http://dev.mysql.com/doc/refman/5.7/en/select.html

您需要按用户对行进行分组,以便为​​每个用户获得一行,但不幸的是,您无法通过这种方式获得他们的最新分数。 您可以获得最大、最小、平均分数和其他计算值。查看 GROUP BY aggregate functions.

的列表

查询

这是获取所需值的查询:

SELECT u.fsname, u.emailaddress, la.score 
FROM users u
INNER JOIN attempts la                # 'la' from 'last attempt'
    ON u.emailaddress = la.emailaddress
LEFT JOIN attempts mr                 # 'mr' from 'more recent' (than last attempt)
    ON la.emailaddress = mr.emailaddress AND la.datetime < mr.datetime
WHERE mr.datetime IS NULL

工作原理

它加入table users(别名u)和table attempts(别名la,"last attempt") 使用 emailaddress 作为匹配列。这是您在查询中已有的联接,我添加了别名,因为它们可以帮助您从那时起减少编写。

接下来,它再次加入 attempts table(别名为 mr,来自“比上次尝试更近”)。它将来自 la 的每次尝试与来自同一用户(由他们的 emailaddress 标识) 的所有尝试进行匹配,这些尝试具有更新的datetimeLEFT JOIN 确保来自 la 的每一行至少匹配来自 mr 的一行。 la 中未在 mr 中匹配的行是每个 emailaddress 具有最大值 datetime 的行。它们与充满 NULL 的行匹配(对于 mr 部分)。

最后,WHERE 子句仅保留从 mr 中选择的行的 datetime 列中具有 NULL 的行。对于 emailaddress.

的每个值,这些行与 la 中的最新条目相匹配

性能备注

为了 运行 快速查询(任何查询!)需要在 JOINWHERE 中使用的列上建立索引, GROUP BYORDER BY 子句。

您不应在 table attempts 中使用 emailaddress 来识别用户。您应该在 table users 上有一个 PK(主键),并将其用作 table attempts 中的 FK(外键)(和其他引用用户的 table)。如果 emailaddress 是 table 的 PK users 将其更改为 UNIQUE INDEX 并使用新的 INTEGER AUTO INCREMENTed 列 userId 作为PK 代替。与字符串列上的索引相比,数字列上的索引更快并且使用更少 space。