2013-08-10 20 views
8

Ho cercato di capirlo da un po 'di tempo e non riesco a farlo funzionare. Ho un tavolo che sembra simile a questo.Come ordinare i risultati raggruppati usando Eloquent?

Tabella: Problemi

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 

Il mio problema è che ho bisogno di risolvere la (facile!), Ma, voglio solo ottenere uno di ogni rivista (magazine_id colonna).

La mia domanda Eloquente fin d'ora è:

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

ho pensato di aggiungere il groupBy('magazine_id') avrebbe aiutato, ma sembra come se mi aiuta solo in parte. I risultati non sono nell'ordine corretto. Quindi, la mia domanda allora è - c'è un modo semplice per aggirare questo?

Ho sperimentato varie risposte a domande simili ma non riesco a implementarlo completamente.

Retrieving the last record in each group

o

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

Più aiuto sarebbe molto apprezzato.

EDIT: Il più vicino che Attualmente è questo:

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 

Tuttavia, non mi sta dando il risultato desiderato a tutti.

risposta

13

È necessario aggiungere una funzione MAX nella clausola SELECT per ogni colonna da ordinare nell'ordine di fine DESC. L'inverso vale per le colonne ordinate nell'ordine finale ASC, è necessario aggiungere la funzione MIN nella clausola SELECT.

Vostri criteri Eloquente deve includere un raw selezionare:

$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(); 

L'unico inconveniente è che è necessario specificare ogni colonna che si desidera recuperare. E non usare il selettore *, sovrascriverà la funzione di aggregazione nella clausola select.


Aggiornamento: Sembra che l'aggiunta del selettore * prima le funzioni di aggregazione nella clausola SELECT funziona troppo. Ciò significa che si riscrive la select crudo come:

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

Credo che mettere il selettore * prima che fa le funzioni di aggregazione priorità su loro colonne.

+1

Impressionante! =) Che ha salvato il mio weekend. – Andreas

+1

Uooow! E 'stato davvero un salvavita. Molte grazie! –

+0

grazie mille questa è la migliore soluzione –

3

Stavo cercando un modo per ordinare i risultati prima del raggruppamento e questa risposta continua a spuntare. Nel mio caso, era per la posta in arrivo di un utente.Avevo bisogno di visualizzare l'ultimo messaggio ricevuto dall'utente in ogni thread di messaggi di cui facevano parte. La mia tabella è simile a questa:

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

La risposta accettata su questa domanda raggruppa i risultati e li ordina. Avevo bisogno di ordinare i risultati per il campo created_at, discendente, prima di raggrupparli in modo da ottenere l'ultimo messaggio da ciascun thread. In ogni caso, qui era la mia soluzione finale dopo un sacco di scavo:

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

Questo costruisce la seguente query:

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

Grazie mille, non ha funzionato per la mia specifica esigenza, il -> parser tosql non sta analizzando abbastanza bene i parametri, ma l'esecuzione di una semplice query raw sql l'ha risolto per me, ha aggiunto il mio propria soluzione :) –

0

In MySQL si può fare qualcosa di simile:

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

In eloquente si farebbe qualcosa del genere: -> groupBy ('campo', 'desc'), tuttavia, l'ordinamento del gruppo non sembra essere un'opzione in eloquente come l'ordine di è.

Potrebbe essere un'istanza in cui è necessario utilizzare una query non elaborata, o eventualmente la funzione massima.

Wade

Problemi correlati