Проблема с SQL-запросом с использованием группировки по и упорядочить по - PullRequest
1 голос
/ 10 января 2011

Я пытаюсь выбрать все комментарии, которые являются последними в их разговоре.Комментарии находятся в одном разговоре, если они имеют одинаковые object_id и type_id.Это запрос, который у меня есть сейчас:

select * from comments 
 where user_id != #{current_user.id} 
 group by type_id, object_id 
 order by created_at desc

Это работает, за исключением того, что комментарии не всегда являются последними в беседе.Как я могу это сделать?Мне нужно, чтобы он работал в mysql и sqlite3.

Ответы [ 5 ]

1 голос
/ 10 января 2011

Этот запрос не очень хорош (вероятно, очень медленный для запуска на вашем сервере), но ...

SELECT 
    MAX(created_at) created_at,
    * 
FROM 
    comments 
WHERE 
    user_id != #{current_user.id} 
GROUP BY 
    type_id, 
    object_id 
ORDER BY
    created_at DESC

РЕДАКТИРОВАТЬ: Просто заметил, что это не работает. Для решения этой проблемы необходима схема таблицы.

1 голос
/ 10 января 2011

Если у вас проблемы с группой, то первое, что нужно сделать, это избегать использования '*'. Это расширение стандартной GROUP BY SQL, предоставляемой MySQL.

Классическая группировка по должна включать все неагрегированные столбцы, используемые в выборке. mySQl позволяет вам избежать самого базового факта и получить некоторую случайность в результате:

Аналогичное расширение MySQL относится к пункт HAVING. Стандарт SQL не позволяет клаузуле HAVING назвать любой столбец, не найденный в группе Предложение BY, если оно не включено в агрегатная функция. MySQL позволяет использование таких столбцов для упрощения расчеты. Это расширение предполагает что будут иметь несгруппированные столбцы одни и те же групповые значения. Иначе, результат неопределенный .

Так что попробуйте обновленную версию запроса с простым выбором.

0 голосов
/ 10 января 2011

Если вы хотите выбрать последние комментарии в каждой группе type_id и object_id, используйте подзапрос:

select c1.*
from comments c1
join (
  select type_id, object_id, max(created_at) last_comment_created_at
  from comments
  where user_id != #{current_user.id} /* indicates 'comment'? */
  group by type_id, object_id
) c2
on c2.type_id = c1.type_id
  and c2.object_id = c1.object_id
  and c2.last_comment_created_at = c1.created_at

Это работает, за исключением нескольких комментариев, имеющих одинаковые значения type_id, object_id и creation_at '.Так что, если есть столбец типа «comment_order», это предпочтительнее, чем «create_at».

0 голосов
/ 10 января 2011

Вы не можете получить нужные результаты, используя только запрос GROUP BY. Причина в том, что нет способа дать СУБД команду выбрать текст комментария, соответствующий последнему комментарию в наборе GROUPed.

Вместо этого сделайте это:

 SELECT * FROM comments 
  WHERE user_id != #{current_user.id} AND created_at = 
    (SELECT MAX(created_at) FROM comments WHERE user_id != #{current_user.id} )

или

 SELECT * FROM comments c1
  WHERE user_id != #{current_user.id} AND NOT EXISTS
    (SELECT * FROM comments c2 
      WHERE user_id != #{current_user.id} AND c2.created_at > c1.created_at )

(я использовал comment_id, так как неясно, что идентифицирует комментарии, но если это object_id, используйте это вместо этого).

0 голосов
/ 10 января 2011

Вот предположение, но вам нужно больше информации о вашей схеме, чтобы быть уверенным.Вам нужен / нужен только самый последний комментарий или вы пытаетесь найти последние n комментариев за "разговор "?

  SELECT *
    FROM comments
   WHERE user_id != ...
ORDER BY type_id,
         object_id,
         created_at DESC
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...