2013-08-10 4 views
8

Я пытался понять это в течение некоторого времени и просто не могу заставить его работать. У меня есть таблица, которая выглядит примерно так.Как упорядочить сгруппированные результаты с помощью «Красноречивого»?

Таблица: Проблемы

id yearly_issue year stock created_at  updated_at  magazine_id 
1 10    2000 1  [timestamp]  [timestamp]  3 
2 12    1994 6  [timestamp]  [timestamp]  10 
3 36    2007 10  [timestamp]  [timestamp]  102 
4 6    2002 7  [timestamp]  [timestamp]  7 
5 6    2002 2  [timestamp]  [timestamp]  5 
6 12    2003 9  [timestamp]  [timestamp]  10 
7 11    2003 12  [timestamp]  [timestamp]  10 

Моя проблема заключается в том, что мне нужно отсортировать его (легко!), Но я только хочу, чтобы получить один из каждого журнала (колонка magazine_id).

Мой Eloquent запрос на данный момент является:

$issues = Issue::where('stock', ($all ? '>=' : '>'), 0) 
    ->orderBy('year', 'desc') 
    ->orderBy('yearly_issue', 'desc') 
    ->take($perpage) 
    ->get(); 

Я думал, добавив groupBy('magazine_id') бы помочь, но это, кажется, как будто он только частично помогает мне. Результаты не в правильном порядке. Итак, теперь мой вопрос - есть ли простой способ обойти это?

Я экспериментировал с различными ответами на подобные вопросы, но я полностью не смог его реализовать.

Retrieving the last record in each group

или

How to get the latest record in each group using GROUP BY?

Дополнительная помощь была бы оценена.

EDIT: Ближайшим Я в настоящее время это:

SELECT i1.*, c.name AS image, m.title AS title 
FROM issues i1 
INNER JOIN covers c ON i1.id = c.issue_id 
INNER JOIN magazines m ON i1.magazine_id = m.id 
JOIN (SELECT magazine_id, MAX(year) year, MAX(yearly_issue) yearly_issue FROM issues GROUP BY magazine_id) i2 
ON i1.magazine_id = i2.magazine_id 
AND i1.year = i2.year 
-- AND i1.yearly_issue = i2.yearly_issue 
WHERE i1.stock ($all ? '>=' : '>') 0 
ORDER BY i1.year DESC, i1.yearly_issue DESC 
LIMIT $perpage 

Однако это не дает мне желаемого результата вообще.

ответ

13

Вам необходимо добавить функцию MAX в предложение SELECT для каждого столбца, заказанного в DESC окончательном порядке. Обратный идет для столбцов, упорядоченных по порядку окончания ASC, вам нужно добавить функцию MIN в пункт SELECT.

Ваш Eloquent запрос должен включать в себя raw выбрать:

$issues = DB::table('issues') 
    ->select(DB::raw('id, max(year) as year, max(yearly_issue) as yearly_issue, stock, created_at, updated_at, magazine_id')) 
    ->groupBy('magazine_id') 
    ->orderBy('year', 'desc') 
    ->orderBy('yearly_issue', 'desc') 
    ->take(10) 
    ->get(); 

Единственным недостатком является то, что вам нужно указать каждый столбец, который вы хотите получить. И не используйте селектор *, он переопределит агрегатную функцию в предложении select.


Update: Похоже, добавив * селектор перед тем агрегатные функции в предложении SELECT тоже работает. Это означает, что вы перезаписать исходный выбор, как:

->select(DB::raw('*, max(year) as year, max(yearly_issue) as yearly_issue')) 

Я думаю, поставив селектор * перед тем делает агрегатные функции отменяет их столбцы.

+1

Awesome! =) Это спасло мои выходные. – Andreas

+1

Uooow! Это была настоящая жизнь. Большое спасибо! –

+0

спасибо, что это лучшее решение –

3

Я искал способ заказать результаты перед группировкой, и этот ответ продолжал появляться. В моем случае это было для почтового ящика сообщения пользователя.Мне нужно было отобразить последнее сообщение, полученное пользователем в каждом потоке сообщений, частью которого они были. Мой стол выглядит так:

-------------------------------------------------------------------- 
| id | sender_id | receiver_id | message | created_at | updated_at | 
-------------------------------------------------------------------- 
| |   |    |   |   |   | 
-------------------------------------------------------------------- 

Принятый ответ на этот вопрос, группирует результаты, а затем сортирует их. Мне нужно было отсортировать результаты по полю created_at, спустившись, прежде чем группировать их, чтобы я получил последнее сообщение из каждого потока. Во всяком случае, здесь было мое окончательное решение после того, как много копания:

$sub = $query->orderBy('created_at', 'desc'); 
return $query->select('*') 
      ->from(DB::raw("({$sub->toSql()}) as sub")) 
      ->groupBy('sender_id'); 

Это строит следующий запрос:

select * from (
    select * from `messages` 
    order by `created_at` desc 
) as sub 
group by `sender_id` 
+1

Большое спасибо, это не сработало для моей конкретной потребности, парсер -> tosql не разбирает параметры довольно хорошо, но запуск простого сырого SQL-запроса разрешил его для меня, добавил мой собственное решение :) –

0

В MySQL вы можете сделать что-то вроде этого:

select * 
    from `UserTable` 
where userId=3 
    group by `field` desc 
    order by `dateActivityComplete` ; 

В красноречивым вы бы сделали что-то вроде этого: -> groupBy ('field', 'desc'), однако, упорядочивание groupBy, похоже, не является вариантом в красноречивом, как и порядок.

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

Wade

Смежные вопросы