【问题标题】:FIRST ORDER BY ... THEN GROUP BY首先订购...然后分组
【发布时间】:2010-09-12 15:59:28
【问题描述】:

我有两张表,一张存储用户,另一张存储用户的电子邮件地址。

  • 表用户:(userIdusernameetc
  • 表用户邮箱:(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 的其他问题,但似乎没有人回答有关此查询模式的问题。

【问题讨论】:

  • 我能问一下您单独存储电子邮件的动机是什么?
  • 您是否使用最新的 emailId 来指示哪个电子邮件地址是用户的主电子邮件地址?这将阻止用户选择较旧的电子邮件地址作为主要地址。您是否考虑过将 emailId 添加到 users 表中?
  • 当用户更改邮箱地址时,添加新地址,旧邮箱地址保留一年后被删除(根据规范)
  • 我猜查询可以通过适当的表格设计变得更有效和更有意义。
  • @NamshubWriter,我已经考虑过了,但它会创建一个我想阻止的循环引用。另外,我在其他情况下也有上述问题,所以我想学习一般情况下的最佳解决方案。

标签: sql mysql


【解决方案1】:

但是这样对每一行都做一个子查询,效率很低

首先,您是否有一个查询计划/时间来证明这一点?您完成它的方式(使用子选择)几乎是“直观”的方式。许多 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;

【讨论】:

    【解决方案2】:

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

    我建议在users 表中添加一个emailId 列。当用户更改其电子邮件地址或将旧电子邮件地址设置为主电子邮件地址时,更新users 表中用户的行以指示当前emailId

    修改代码以进行此更新后,您可以返回并更新旧数据,为所有用户设置 emailId

    或者,您可以将email 列添加到users 表中,这样您就不必进行联接来获取用户的当前电子邮件地址。

    【讨论】:

      猜你喜欢
      • 2021-10-30
      • 1970-01-01
      • 2014-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多