2013-08-06 16 views
49

Ok dopo ore di ricerca e utilizzando ancora DB :: selezionare Devo fare questa domanda. Perché sto per mandare via il mio computer;).Laravel Fluent Query Builder Unisciti alla sottoquery

Voglio ottenere l'ultimo input di un utente (base sul timestamp). Posso fare questo con lo SQL prime

SELECT c.*, p.* 
FROM users c INNER JOIN 
(
    SELECT user_id, 
      MAX(created_at) MaxDate 
    FROM `catch-text` 
    GROUP BY user_id 
) MaxDates ON c.id = MaxDates.user_id INNER JOIN 
    `catch-text` p ON MaxDates.user_id = p.user_id 
    AND MaxDates.MaxDate = p.created_at 

ho ricevuto questa domanda da un altro post here su StackOverflow.

Ho provato a fare tutto ciò con il fluent query builder in Laravel, ma senza successo.

So che il manuale dice che si può fare questo:

DB::table('users') 
    ->join('contacts', function($join) 
    { 
     $join->on('users.id', '=', 'contacts.user_id')->orOn(...); 
    }) 
    ->get(); 

Ma questo non aiuta molto perché non vedo come potrei usare una sottoquery lì? Chiunque può illuminare la mia giornata?

risposta

105

Ok per tutti voi là fuori che sono arrivati ​​qui nella disperazione alla ricerca dello stesso problema. Spero che lo troverai più veloce di allora, O.

Ecco come è risolto. JoostK mi ha detto al Github che "il primo argomento a cui aderire è il tavolo (oi dati) a cui ti unisci". E aveva ragione.

Ecco il codice. Tabella e nomi diversi, ma l'idea ti sarà chiara? Si t

DB::table('users') 
     ->select('first_name', 'TotalCatches.*') 

     ->join(DB::raw('(SELECT user_id, COUNT(user_id) TotalCatch, 
       DATEDIFF(NOW(), MIN(created_at)) Days, 
       COUNT(user_id)/DATEDIFF(NOW(), MIN(created_at)) 
       CatchesPerDay FROM `catch-text` GROUP BY user_id) 
       TotalCatches'), 
     function($join) 
     { 
      $join->on('users.id', '=', 'TotalCatches.user_id'); 
     }) 
     ->orderBy('TotalCatches.CatchesPerDay', 'DESC') 
     ->get(); 
+3

Questo pacchetto dovrebbe per fornire un set di strumenti PHP per creare query, tuttavia abbiamo bisogno di annotare la query e di iniettarla con l'istruzione 'selectRaw'! Hai avuto la fortuna di passare un oggetto di query fluente alla query, invece della stringa di query? – HPM

+0

Questo diventa impossibile se si ha un parametro nella sottoselezione - vedere la risposta di ph4r05 ad esempio, ma non sono sicuro se potrebbe essere semplificato per evitare quei brutti toSql e aggiungereBinding – JustAMartin

6

ero alla ricerca di una soluzione ad un bel problema correlato: trovare i nuovi record per gruppo, che è una specializzazione di un tipico greatest-n-per-group con N = 1.

La soluzione prevede il problema che stanno trattando qui (cioè, come costruire la query in Eloquent), quindi la sto postando perché potrebbe essere utile per gli altri. Dimostra un modo più pulito di costruzione di sub-query usando la potente interfaccia fluente di Eloquent con più colonne di join e la condizione where all'interno della sotto-selezione unita.

Nel mio esempio voglio recuperare i risultati della scansione DNS più recenti (tabella scan_dns) per gruppo identificato da watch_id. Costruisco la sub-query separatamente.

Lo SQL voglio eloquente generate:

SELECT * FROM `scan_dns` AS `s` 
INNER JOIN (
    SELECT x.watch_id, MAX(x.last_scan_at) as last_scan 
    FROM `scan_dns` AS `x` 
    WHERE `x`.`watch_id` IN (1,2,3,4,5,42) 
    GROUP BY `x`.`watch_id`) AS ss 
ON `s`.`watch_id` = `ss`.`watch_id` AND `s`.`last_scan_at` = `ss`.`last_scan` 

l'ho fatto nel modo seguente:

// table name of the model 
$dnsTable = (new DnsResult())->getTable(); 

// groups to select in sub-query 
$ids = collect([1,2,3,4,5,42]); 

// sub-select to be joined on 
$subq = DnsResult::query() 
    ->select('x.watch_id') 
    ->selectRaw('MAX(x.last_scan_at) as last_scan') 
    ->from($dnsTable . ' AS x') 
    ->whereIn('x.watch_id', $ids) 
    ->groupBy('x.watch_id'); 
$qqSql = $subq->toSql(); // compiles to SQL 

// the main query 
$q = DnsResult::query() 
    ->from($dnsTable . ' AS s') 
    ->join(
     DB::raw('(' . $qqSql. ') AS ss'), 
     function(JoinClause $join) use ($subq) { 
      $join->on('s.watch_id', '=', 'ss.watch_id') 
       ->on('s.last_scan_at', '=', 'ss.last_scan') 
       ->addBinding($subq->getBindings()); 
       // bindings for sub-query WHERE added 
     }); 

$results = $q->get(); 
0

query con sub query in laravel

$resortData = DB::table('resort') 
     ->leftJoin('country', 'resort.country', '=', 'country.id') 
     ->leftJoin('states', 'resort.state', '=', 'states.id') 
     ->leftJoin('city', 'resort.city', '=', 'city.id') 
     ->select('resort.*', 'country.name as country_name', 'states.name as state_name','city.name as city_name', DB::raw("(SELECT GROUP_CONCAT(amenities.name) from resort_amenities LEFT JOIN amenities on amenities.id= resort_amenities.amenities_id WHERE resort_amenities.resort_id=resort.id) as amenities_name"))->groupBy('resort.id') 
     ->orderBy('resort.id', 'DESC') 
     ->get(); 
Problemi correlati