Как правильно использовать группу в строгом режиме? - PullRequest
1 голос
/ 24 января 2020

У меня есть таблица для таких сообщений:

CREATE TABLE `message` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `from_id` bigint(20) unsigned NOT NULL,
    `to_id` bigint(20) unsigned NOT NULL,
    `body` text COLLATE utf8mb4_unicode_ci NOT NULL,
    `status` tinyint(4) NOT NULL,
    `created_at` timestamp NULL DEFAULT NULL,  
    PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

и я пытаюсь выбрать каждое последнее сообщение от userX к userY, но mysql всегда говорит, что у меня есть неагрегированные столбцы (без only_full_group_by хорошо работает). Как я могу выбрать это в строгом режиме? Не рабочий запрос, например:

select
     t1.created_at,
     t1.from_id,
     t1.to_id,
     t1.body,
     t1.status,
     ( select created_at from test1.message where from_id = t1.from_id order by created_at desc limit 1 ) as last_timestamp

from test1.message as t1
group by t1.from_id 
having t1.created_at = last_timestamp

Ответы [ 2 ]

0 голосов
/ 24 января 2020

Вам даже не нужно использовать GROUP BY здесь, и без него ваш текущий запрос должен действительно быть действительным:

SELECT
    t1.created_at,
    t1.from_id,
    t1.to_id,
    t1.body,
    t1.status,
    (SELECT t2.created_at FROM test1.message t2
     WHERE t2.from_id = t1.from_id
     ORDER BY t2.created_at DESC LIMIT 1) AS last_timestamp
FROM test1.message AS t1
HAVING t1.created_at = last_timestamp;

MySQL перегружен оператор HAVING для использования вместо предложения WHERE с дополнительной возможностью, что псевдонимы, определенные в предложении SELECT, могут фактически использоваться там.

0 голосов
/ 24 января 2020

Не агрегировать - вместо этого фильтруйте.

В одном варианте используется коррелированный подзапрос, который вычисляет максимум created_at для пользователя:

 select m.*
 from message m
 where m.created_at = (
      select max(m1.created_at) from message m1 where m1.from_id = m.from_id
)

Вы также можете использовать анти-запрос. left join pattern:

select m.*
from message m
left join message m1 on m1.from_id = m.from_id and m1.createt_at > m.created_at
where m1.id is null

Это фразы как: получить записи, из которых не существует другой записи с таким же from_id и большим created_at.

...