如何从user和usermeta表中选择最后一个用户信息?

时间:2018-08-20 15:18:45

标签: mysql sql entity-attribute-value

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

  

用户
  user_id-用户名-电话

     

UserMeta
  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";

3 个答案:

答案 0 :(得分:5)

您可以使用以下内容:

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

答案 1 :(得分:5)

尽管我强烈建议您不要执行此操作,但我不会尝试改变您的想法。 尽管有很多方法可以实现此目的,但我相信下面的查询将对性能造成的影响最小(不使用聚合)。

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语句。这些只是为了确保随着数据库的增长而至少具有一定性能的最低要求。

答案 2 :(得分:0)

我想提出一个基于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