2010-09-12 40 views
9

我有两个表,一个存储用户,另一个存储用户的电子邮件地址。第一个命令...然后是

  • 表用户:(userIdusernameetc
  • 表USEREMAIL:(emailIduserIdemail

我愿做一个查询,让我获取最新的邮件地址以及用户记录。
我基本上寻找一个查询,说

FIRST ORDER BY userEmail.emailId DESC 
THEN GROUP BY userEmail.userId 

这是可以做到的:

SELECT 
    users.userId 
, users.username 
, (
    SELECT 
     userEmail.email 
    FROM userEmail 
    WHERE userEmail.userId = users.userId 
    ORDER BY userEmail.emailId DESC 
    LIMIT 1 
) AS email 
FROM users 
ORDER BY users.username; 

但这一个子查询的每一行,是非常低效的。 (在我的程序逻辑中,执行2个单独的查询并将它们'连接'在一起会更快)。


直观的查询写什么,我想应该是:

SELECT 
    users.userId 
, users.username 
, userEmail.email 
FROM users 
LEFT JOIN userEmail USING(userId) 
GROUP BY users.userId 
ORDER BY 
    userEmail.emailId 
, users.username; 

但是,这并不能作为我想。 (GROUP BY在排序之前执行,因此ORDER BY userEmail.emailId无关)。


所以我的问题是:
是否有可能写第一个查询而不使用子查询的?


我已经搜索并阅读了其他关于stackoverflow的问题,但似乎没有人回答关于此查询模式的问题。

+1

我能问你的动机是存储电子邮件的分开是什么? – RobertPitt 2010-09-12 16:11:08

+1

您是否使用最新的emailId作为哪个电子邮件地址是用户的主要电子邮件地址的指示?这将阻止用户选择较旧的电子邮件地址作为主要电子邮件地址你有没有考虑过在users表中添加emailId? – NamshubWriter 2010-09-12 16:12:09

+0

当用户更改他们的电子邮件地址时,新的地址被添加,旧的电子邮件地址被保留一年,然后被删除(根据规格) – Jacco 2010-09-12 16:14:57

回答

4

但这一个子查询的每一行,是非常低效的

首先,你有一个查询计划/定时演示呢?你做这件事的方式(使用子选择)是非常直观的方式。许多DBMS(尽管我不确定MySQL)对这种情况进行了优化,并且只能执行一次查询。

另外,你应该能够创建一个只(user id, latest email id)元组和JOIN到一个子表:

SELECT 
    users.userId 
, users.username 
, userEmail.email 
FROM users 
INNER JOIN 
     (SELECT userId, MAX(emailId) AS latestEmailId 
     FROM userEmail GROUP BY userId) 
     AS latestEmails 
     ON (users.userId = latestEmails.userId) 
INNER JOIN userEmail ON 
     (latestEmails.latestEmailId = userEmail.emailId) 
ORDER BY users.username; 
1

如果这是您经常查询的查询,我建议优化您的表以处理此问题。

我建议在users表中增加一个emailId列。当用户更改他们的电子邮件地址,或将旧的电子邮件地址作为主要电子邮件地址,更新users表用户的行表示当前emailId

一旦您修改代码来执行此更新,你可以去返回并更新您的旧数据,以便为所有用户设置emailId

或者,您可以将email列添加到users表中,因此您无需进行连接即可获取用户当前的电子邮件地址。

相关问题