2014-07-18 11 views
44

Mi piacerebbe ottenere valore dal seguente SQL utilizzando ORI di Eloquent.Come selezionare dalla sottoquery utilizzando Laravel Query Builder?

- SQL

SELECT COUNT(*) FROM 
(SELECT * FROM abc GROUP BY col1) AS a; 

Poi ho considerato quanto segue.

- Codice

$sql = Abc::from('abc AS a')->groupBy('col1')->toSql(); 
$num = Abc::from(\DB::raw($sql))->count(); 
print $num; 

Sto cercando una soluzione migliore.

Per favore dimmi la soluzione più semplice.

risposta

80

Oltre a @ La risposta di delmadord e i vostri commenti:

Attualmente non esiste un metodo per creare la sottoquery nella clausola FROM, quindi è necessario utilizzare manualmente gli statum grezzi t, poi, se necessario, si unirà tutte le associazioni:

$sub = Abc::where(..)->groupBy(..); // Eloquent Builder instance 

$count = DB::table(DB::raw("({$sub->toSql()}) as sub")) 
    ->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder 
    ->count(); 

mente che è necessario per attacchi di unione nel corretto ordine. Se si dispone di altre clausole legate, li si deve mettere dopo mergeBindings:

$count = DB::table(DB::raw("({$sub->toSql()}) as sub")) 

    // ->where(..) wrong 

    ->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder 

    // ->where(..) correct 

    ->count(); 
+0

Grazie! Non conoscevo il metodo unioneBindings. L'espressione della sottoquery per codice è complessa ... – quenty658

+0

Ciao, ho ricevuto l'errore seguente 'L'argomento 1 passato a Illuminate \ Database \ Query \ Builder :: mergeBindings() deve essere un'istanza di Illuminate \ Database \ Query \ Builder, istanza di Illuminate \ Database \ Eloquent \ Builder dato', cosa mi sono perso? – sulaiman

+0

@sulaiman Hai perso la parte '$ sub-> getQuery()', che ottiene l'oggetto sottostante 'Query \ Builder'. –

-2

Avete bisogno della sub-query? Si potrebbe provare qualcosa di simile

$num = Abc::groupBy('col1')->get()->count();

Non è l'ideale se hai milioni di righe, però.

+0

Grazie reply.The SQL è in realtà più complessa e il numero di record sono anche molti. – quenty658

0

Non è stato possibile creare il codice per eseguire la query desiderata, l'AS è un alias solo per la tabella abc, non per la tabella derivata. Laravel Query Builder non supporta implicitamente gli alias di tabelle derivate, DB :: raw è probabilmente necessario per questo.

La soluzione più rettilineo potevo venuto in mente è quasi identico al vostro, ma produce la query come avete chiesto:

$sql = Abc::groupBy('col1')->toSql(); 
$count = DB::table(DB::raw("($sql) AS a"))->count(); 

La query prodotta è

select count(*) as aggregate from (select * from `abc` group by `col1`) AS a; 
+0

Grazie per la risposta. C'è un problema nel metodo di "Abc :: from (???) e DB :: table (???)". $ sql = Abc :: where ('id', '=', $ id) -> groupBy ('col1') -> toSql(); $ count = DB :: table (DB :: raw ("($ sql) AS a")) -> count(); Errore SQL si verifica nel codice precedente. - dove e parametro assegnato! – quenty658

0

Mi piace fare qualcosa di simile:

Message::select('*') 
->from(DB::raw("(SELECT * FROM `messages` 
        WHERE `to_id` = ".Auth::id()." AND `isseen` = 0 
        GROUP BY `from_id` asc) as `sub`")) 
->count(); 

Non è molto elegante, ma è semplice.

9

La soluzione di @JarekTkaczyk è esattamente ciò che stavo cercando. L'unica cosa che mi manca è come farlo quando si utilizzano le query DB::table(). In questo caso, questo è come lo faccio:

$other = DB::table(DB::raw("({$sub->toSql()}) as sub"))->select(
    'something', 
    DB::raw('sum(qty) as qty'), 
    'foo', 
    'bar' 
); 
$other->mergeBindings($sub); 
$other->groupBy('something'); 
$other->groupBy('foo'); 
$other->groupBy('bar'); 
print $other->toSql(); 
$other->get(); 

atention speciale come fare il mergeBindings senza utilizzare il metodo

0

getQuery() Da laravel 5.5 c'è un metodo dedicato per subquery e si può usare in questo modo:

Abc::subSelect(function($q) { $q->select('*')->groupBy('col1'); }, 'a')->count('a.*');

o

Abc::subSelect(Abc::select('*')->groupBy('col1'), 'a')->count('a.*');

Problemi correlati