Я использую MySQL и у меня есть две таблицы в форме ниже:

< Сильный > Пользователь :
user_id - user_name - телефон

< Сильный > 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";
7
MHF 20 Авг 2018 в 18:18

3 ответа

Лучший ответ

Вы можете использовать следующее:

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

5
Sebastian Brosch 23 Авг 2018 в 08:55

Я хочу предложить решение, основанное на использовании ROW_NUMBER функция . Это решение широко используется в других базах данных. Например, посмотрите здесь. Но ваша версия MySQL не поддерживает функцию ROW_NUMBER, и я использовал ее эмуляцию, описанную здесь, Чтобы проверить мое решение, нажмите здесь.

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
0
Andrei Odegov 29 Авг 2018 в 14:44

Хотя я настоятельно советую против такой реализации, я не буду пытаться передумать. Хотя есть много способов добиться этого, я считаю, что приведенный ниже запрос будет иметь наименьшее снижение производительности (без использования агрегатов).

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, после чего группируем. Таким образом, он сохраняет порядок сортировки.

Пожалуйста, ознакомьтесь с рабочим решением здесь, также обратите внимание, что я добавил 2 оператора INDEX CREATE к примеру сценария создания базы данных в левой панели. Это минимум, чтобы обеспечить хоть какую-то адекватную производительность по мере роста базы данных.

5
Harly H. 24 Авг 2018 в 13:36
51933861