2013-08-06 38 views
49

Được rồi sau giờ nghiên cứu và vẫn đang sử dụng DB :: chọn Tôi phải đặt câu hỏi này. Bởi vì tôi chuẩn bị máng máy tính của mình;).Trình tạo truy vấn thông thạo Laravel Tham gia với truy vấn phụ

Tôi muốn nhận dữ liệu nhập cuối cùng của người dùng (dựa trên dấu thời gian). Tôi có thể làm điều này với sql liệu

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 

Tôi đã truy vấn này từ một bài here trên stackoverflow.

Tôi đã thử mọi thứ để làm điều này với trình tạo truy vấn thông thạo trong Laravel tuy nhiên không thành công.

Tôi biết hướng dẫn nói rằng bạn có thể làm điều này:

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

Nhưng đó không phải đang giúp nhiều vì tôi không thấy làm thế nào tôi có thể sử dụng một subquery đó? Bất cứ ai có thể thắp sáng ngày của tôi?

Trả lời

105

Ok cho tất cả các bạn ở đó đã đến đây trong tuyệt vọng tìm kiếm cùng một vấn đề. Tôi hy vọng bạn sẽ tìm thấy điều này nhanh hơn sau đó tôi đã làm;

Đây là cách giải quyết. JoostK nói với tôi tại github rằng "lập luận đầu tiên để tham gia là bảng (hoặc dữ liệu) bạn đang tham gia.". Và anh ta đã đúng.

Đây là mã. Bảng và tên khác nhau nhưng bạn sẽ có ý tưởng đúng không? Nó 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

Gói này được coi để cung cấp một công cụ PHP được thiết lập để xây dựng các truy vấn, nhưng chúng ta cần ghi lại truy vấn và tiêm nó bằng câu lệnh 'selectRaw'! Bạn có may mắn khi chuyển đối tượng truy vấn thông thạo cho truy vấn, thay vì chuỗi truy vấn không? – HPM

+0

Điều này trở thành không thể nếu bạn có một tham số trong subselect - xem câu trả lời @ ph4r05 ví dụ, nhưng tôi không chắc chắn nếu nó có thể được đơn giản hóa để tránh những xấu xí toSql và addBinding – JustAMartin

6

tôi đang tìm kiếm một giải pháp cho một vấn đề khá liên quan: tìm kiếm các hồ sơ mới nhất cho mỗi nhóm mà là một chuyên môn hóa của một điển hình greatest-n-per-group với N = 1.

Các giải pháp liên quan đến vấn đề bạn đang xử lý ở đây (ví dụ, làm thế nào để xây dựng các truy vấn trong Eloquent) vì vậy tôi đăng nó vì nó có thể hữu ích cho người khác. Nó thể hiện cách xây dựng truy vấn phụ rõ ràng hơn bằng cách sử dụng giao diện thông thạo Eloquent mạnh mẽ với nhiều cột nối và điều kiện where bên trong lựa chọn phụ đã tham gia.

Trong ví dụ của tôi, tôi muốn tìm nạp kết quả quét DNS mới nhất (bảng scan_dns) cho mỗi nhóm được xác định bởi watch_id. Tôi tạo riêng truy vấn phụ.

SQL Tôi muốn hùng hồn cho 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` 

tôi đã làm nó theo cách sau:

// 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 với truy vấn phụ trong 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(); 
Các vấn đề liên quan