Выборка из нескольких таблиц с сортировкой по времени каждой из них

Рейтинг: 0Ответов: 1Опубликовано: 11.06.2023

Немного упрощу таблицы. У меня есть 6 таблиц.

  1. modemsInfo(id, idUser, idGroup, infoText) // информация о модемах
  2. groupModems(id, idUser, nameGroup) // информация о группах в которой могут быть модемы
  3. data(idModem, Time, text) // общая информация которую прислали модемы
  4. dataResponseConfig(idModem, Time, text) // конфигурационная инфа пришедшая от модемов
  5. dataResponseReset(idModem, Time, text) // результаты сбросов пришедшие от модемов
  6. queueSmsLog(idModem, Time, text) // смс которые отправлялись модемам

Мне нужно выдать инфу от модемов пользователя. Я выбираю модем и приклеиваю к нему последний ответ (сортирую в колонке(Time) и ставлю Limit 1) из таблиц: общий(data), конфига(dataResponseConfig), сброса(dataResponseReset) и смсЛога(queueSmsLog). Все работает до момента пока нет одинаковых значений времени(Time) в любой таблице. Появляются дубликаты. Использую такой запрос. Чувствую, что проблема в конце запроса, но как исправить уже знаний не хватает.

SELECT gM.nameGroup as nameGroup, mI.infoText, qSL.Time, qSL.text,
       dRC.Time ,dRR.Time, data.Time, data.text
FROM groupModems gM
 left outer JOIN modemsInfo mI ON mI.idUser = gM.idUser AND mI.idGroup = gM.id
 left outer JOIN data ON mI.id = data.idModem
 left outer JOIN queueSmsLog qSL ON mI.id = qSL.idModem
 left outer JOIN dataResponseConfig dRC ON mI.id = dRC.idModem
 left outer JOIN dataResponseReset dRR ON mI.id = dRR.idModem
WHERE gM.idUser = :user_id
AND (data.Time = (SELECT `Time`
                  FROM data
                  WHERE  mI.id = data.idModem
                  ORDER BY `Time` DESC
                  LIMIT 1)
     OR data.Time IS NULL)
AND (dRC.Time = (SELECT `Time`
                 FROM dataResponseConfig
                 WHERE  mI.id = dataResponseConfig.idModem
                 ORDER BY `Time` DESC
                 LIMIT 1)
     OR dRC.Time IS NULL)
AND (dRR.Time = (SELECT `Time`
                 FROM dataResponseReset
                 WHERE  mI.id = dataResponseReset.idModem
                 ORDER BY `Time` DESC
                 LIMIT 1)
     OR dRR.Time IS NULL)
AND (qSL.Time = (SELECT  `Time`
                 FROM queueSmsLog
                 WHERE  mI.id = queueSmsLog.idModem
                 ORDER BY id DESC
                 LIMIT 1)
    OR qSL.Time IS NULL) 

IS NULL - использовал на случай если вообще нет никакой информации в таблицах c ответами от модемов

Ответы

▲ 1Принят

Если предположить, что в таблицах вроде dataResponseConfig есть собственные id записей (а куда же без них, если вдруг нет, добавьте), то выходит что то такое:

SELECT gM.nameGroup as nameGroup, mI.infoText,
       qSL.Time, qSL.text,
       (SELECT max(`Time`) FROM dataResponseConfig dRC WHERE mI.id = dRC.idModem) as dRC_Time,
       (SELECT max(`Time`) FROM dataResponseReset dRR WHERE mI.id = dRR.idModem) as dRR_Time,
       data.Time, data.text
  FROM groupModems gM
  left outer JOIN modemsInfo mI ON mI.idUser = gM.idUser AND mI.idGroup = gM.id
  left outer JOIN data ON mI.id = data.idModem
  left outer JOIN queueSmsLog qSL ON mI.id = qSL.idModem
WHERE gM.idUser = :user_id
  AND ( (data.Time, data.id) = (SELECT `Time`, id FROM data
                                 WHERE mI.id = data.idModem
                                 ORDER BY `Time` DESC, id desc LIMIT 1)
     OR data.Time IS NULL)
  AND ( (qSL.Time, qSL.id) = (SELECT `Time`, id FROM queueSmsLog
                               WHERE mI.id = queueSmsLog.idModem
                               ORDER BY `Time` DESC, id DESC LIMIT 1)
    OR qSL.Time IS NULL)

P.S. Если все именно так, как описана структура таблиц в вопросе и колонки id нет, то ее стоит добавить, работать с записями без явной уникальности крайне сложно. Тут конечно есть варианты вытаскивать что то вроде select max(concat(привести_к_строке(Time), text)) ... и потом обратно разбирать объединенную строку на time и text, но это довольно громоздко выглядит и вообще не удобно.