【问题标题】:How select last user information from user and usermeta tables?如何从 user 和 usermeta 表中选择最后一个用户信息?
【发布时间】:2018-08-20 15:18:44
【问题描述】:

我正在使用 mysql,我有两个表格,格式如下:

用户
user_id - user_name - 电话

用户元
user_meta_id - user_id - meta_key - meta_value - meta_date

我有一些记录如下:

user_id: 23  
meta_key: gender  
meta_value: male  
meta_date: 1534533650



user_id: 23  
meta_key: city  
meta_value: london  
meta_date: 1534533650



user_id: 23  
meta_key: name  
meta_value: jack  
meta_date: 1534533650  



user_id: 25  
meta_key: name  
meta_value: Jamie 
meta_date: 1534593881  

user_id: 25  
meta_key: gender  
meta_value: male 
meta_date: 1534593881  

user_id: 23  
meta_key: gender  
meta_value: female  
meta_date: 1534595971

user_id: 23  
meta_key: city  
meta_value: liverpool  
meta_date: 1534595971 

And ...

我需要获取所有已注册最新更改的用户信息(user_id = 23),例如:

user_id: 23  
meta_key: name  
meta_value: Jamie  
meta_date: 1534533650 

user_id: 23  
meta_key: city  
meta_value: liverpool  
meta_date: 1534595971  

user_id: 23  
meta_key: gender  
meta_value: female  
meta_date: 1534595971  

此操作的查询很复杂,我很困惑,请帮助我,
我使用了这个但没有得到正确的结果:

    "SELECT kmu.*
            FROM user_meta kmu
            INNER JOIN
            (SELECT `meta_key`, `meta_value`, MAX(`meta_date`) AS MaxDateTime
            FROM user_meta
            GROUP BY meta_key) groupedtt
            ON user_id=:id
            AND kmu.meta_key = groupedtt.meta_key
            AND kmu.meta_date = groupedtt.MaxDateTime";

【问题讨论】:

  • 为什么不在 group by 子句中使用meta_value
  • @Ankit-bajpai 输出没有区别(按 meta_key 分组 = 按 meta_value 分组)。你能指导我更多吗?
  • 对您来说最新的变化是什么?最后 3 个 id 取决于他们的 meta_date?
  • 慰问 - 您已经结合了多种“复杂”设计模式(EAV、历史等);查询复杂性将比比皆是,性能将受到影响。如果您计划拥有超过几千个“用户”,您将看到性能问题。
  • @Rick James 谢谢,您还会在 WordPress 中看到相同的功能,而且一切看起来都不错,那么有什么区别?

标签: mysql sql entity-attribute-value


【解决方案1】:

您可以使用以下内容:

SELECT `user`.*, user_meta.meta_key, user_meta.meta_value, user_meta.meta_date 
FROM `user` INNER JOIN (
    SELECT user_id, meta_key, MAX(meta_date) AS meta_date 
    FROM user_meta 
    GROUP BY user_id, meta_key
) meta_select ON `user`.user_id = meta_select.user_id 
INNER JOIN user_meta ON meta_select.meta_key = user_meta.meta_key 
    AND meta_select.user_id = user_meta.user_id 
    AND meta_select.meta_date = user_meta.meta_date
WHERE `user`.user_id = 23

演示: https://www.db-fiddle.com/f/euqvGNW6PguCG495Yi9dTa/1

【讨论】:

    【解决方案2】:

    虽然我强烈建议您反对这种实施方式,但我不会试图改变您的想法。 尽管有很多方法可以实现这一点,但我相信下面的查询将具有最小的性能损失(不使用聚合)。

    SELECT 
      user.*, meta.meta_key, meta.meta_value, meta.meta_date FROM user 
    LEFT JOIN 
      (
        SELECT * FROM 
          (SELECT * FROM user_meta WHERE user_id = 23 ORDER BY meta_date DESC) sub 
        GROUP BY 
          sub.meta_key
      ) meta 
    ON 
      user.user_id = meta.user_id
    ORDER BY 
      meta.meta_key;
    

    为了便于阅读,我将查询格式化为这样。您可能会看到我正在使用 2 个嵌套子查询。该要求来自这样一个事实,即当您使用 GROUP BY 子句时,ORDER BY 无效。因此,首先我们选择行并按日期 desc 对它们进行排序,然后进行分组。这样它就保留了排序顺序。

    请查看工作解决方案here,另请注意,我在左侧窗格的示例数据库创建脚本中添加了 2 个 INDEX CREATE 语句。随着数据库的增长,这些只是确保至少有足够性能的最低要求。

    【讨论】:

      【解决方案3】:

      我想提出一个基于使用ROW_NUMBER 函数的解决方案。该解决方案已在其他数据库中广泛使用。例如,查看here。但是你的 MySQL 版本不支持 ROW_NUMBER 函数,我使用了here 描述的模拟。要查看我的解决方案,请单击here

      SELECT
        *
      FROM `user` AS u
      LEFT JOIN (
        SELECT
          t.*
        FROM (
          SELECT
            @rn := IF(@uid = user_id AND @mk = meta_key, @rn + 1, 1) AS rn,
            @uid := user_id AS uid,
            @mk := meta_key AS mk,
            um.*
          FROM `user_meta` AS um
          CROSS JOIN (SELECT @uid := 0, @mk := 0, @rn := 0) AS i
          ORDER BY um.user_id, um.meta_key, um.meta_date DESC
        ) AS t
        WHERE t.rn = 1
      ) AS r ON u.user_id = r.user_id
      WHERE u.user_id = 23
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-12-28
        • 2018-02-05
        • 2018-06-20
        • 1970-01-01
        • 1970-01-01
        • 2014-04-07
        • 1970-01-01
        相关资源
        最近更新 更多