THAM GIA với các điều kiện bổ sung bằng cách sử dụng trình tạo truy vấn hoặc Eloquent


93

Tôi đang cố gắng thêm một điều kiện bằng cách sử dụng truy vấn JOIN với Bộ tạo truy vấn Laravel.

<?php

$results = DB::select('
       SELECT DISTINCT 
          *
          FROM 
             rooms 
                LEFT JOIN bookings  
                   ON rooms.id = bookings.room_type_id
                  AND (  bookings.arrival between ? and ?
                      OR bookings.departure between ? and ? )
          WHERE
                bookings.room_type_id IS NULL
          LIMIT 20',
    array('2012-05-01', '2012-05-10', '2012-05-01', '2012-05-10')
);

Tôi biết tôi có thể sử dụng Biểu thức thô nhưng sau đó sẽ có các điểm chèn SQL. Tôi đã thử cách sau với Trình tạo truy vấn nhưng truy vấn được tạo (và rõ ràng là kết quả truy vấn) không như tôi dự định:

$results = DB::table('rooms')
    ->distinct()
    ->leftJoin('bookings', function ($join) {
        $join->on('rooms.id', '=', 'bookings.room_type_id');
    })
    ->whereBetween('arrival', array('2012-05-01', '2012-05-10'))
    ->whereBetween('departure', array('2012-05-01', '2012-05-10'))
    ->where('bookings.room_type_id', '=', null)
    ->get();

Đây là truy vấn được tạo bởi Laravel:

select distinct * from `room_type_info`
    left join `bookings` 
on `room_type_info`.`id` = `bookings`.`room_type_id` 
where `arrival` between ? and ? 
    and `departure` between ? and ? 
    and `bookings`.`room_type_id` is null

Như bạn có thể thấy, đầu ra truy vấn không có cấu trúc (đặc biệt là trong phạm vi JOIN). Có thể thêm các điều kiện bổ sung theo THAM GIA không?

Làm cách nào để tôi có thể tạo cùng một truy vấn bằng cách sử dụng Trình tạo truy vấn của Laravel (nếu có thể) Sử dụng Eloquent sẽ tốt hơn hay nên ở lại với DB :: select?

Câu trả lời:


139
$results = DB::table('rooms')
                     ->distinct()
                     ->leftJoin('bookings', function($join)
                         {
                             $join->on('rooms.id', '=', 'bookings.room_type_id');
                             $join->on('arrival','>=',DB::raw("'2012-05-01'"));
                             $join->on('arrival','<=',DB::raw("'2012-05-10'"));
                             $join->on('departure','>=',DB::raw("'2012-05-01'"));
                             $join->on('departure','<=',DB::raw("'2012-05-10'"));
                         })
                     ->where('bookings.room_type_id', '=', NULL)
                     ->get();

Không hoàn toàn chắc chắn nếu mệnh đề between có thể được thêm vào nối trong laravel.

Ghi chú:

  • DB::raw() hướng dẫn Laravel không đặt ngược dấu ngoặc kép.
  • Bằng cách chuyển một bao đóng để tham gia các phương thức, bạn có thể thêm nhiều điều kiện tham gia vào nó, on()sẽ thêm ANDđiều kiện và orOn()sẽ thêm ORđiều kiện.

Cảm ơn vì câu trả lời. Thật không may, truy vấn được tạo hơi khác vì điều kiện tham gia bây giờ có and arrival >= ? and arrival <= ? and departure >= ? and departure <= ?thay thế AND ( r.arrival between ? and ? OR r.departure between ? and ? )(vui lòng lưu ý ORđiều khoản). Điều này thêm các hàng bổ sung để dẫn đến kết quả không nên có ở đó. Tôi đoán không thể tạo tất cả các loại điều kiện tham gia bằng QB.
Dede

1
Trên thực tế, tôi nhận thấy rằng? không được thêm vào mệnh đề ON. Các giá trị đó trong ON không được tham số hóa và không được bảo vệ khỏi SQL injection. Tôi đã đăng một câu hỏi đang cố gắng tìm ra giải pháp.
lập trình viên

3
điều này không trả lời câu hỏi ban đầu có một hoặc mệnh đề bị bỏ qua trong câu trả lời này.
ionescho

Giải pháp hoàn hảo. Chỉ cần nhớ sử dụng DB :: raw khi sử dụng một giá trị, nếu không Laravel (ít nhất là trong 5.6.29) thêm dấu ngoặc kép và "phá vỡ" mục tiêu.
Adrian Hernandez-Lopez

35

Bạn có thể sao chép các dấu ngoặc đó trong phép nối bên trái:

LEFT JOIN bookings  
               ON rooms.id = bookings.room_type_id
              AND (  bookings.arrival between ? and ?
                  OR bookings.departure between ? and ? )

->leftJoin('bookings', function($join){
    $join->on('rooms.id', '=', 'bookings.room_type_id');
    $join->on(DB::raw('(  bookings.arrival between ? and ? OR bookings.departure between ? and ? )'), DB::raw(''), DB::raw(''));
})

Sau đó, bạn sẽ phải đặt các ràng buộc sau bằng cách sử dụng "setBindings" như được mô tả trong bài đăng SO này: Làm thế nào để liên kết các tham số với một truy vấn DB thô trong Laravel được sử dụng trên một mô hình?

Nó không đẹp nhưng nó hoạt động.


32

Nếu bạn có một số thông số, bạn có thể làm điều này.

    $results = DB::table('rooms')
    ->distinct()
    ->leftJoin('bookings', function($join) use ($param1, $param2)
    {
        $join->on('rooms.id', '=', 'bookings.room_type_id');
        $join->on('arrival','=',DB::raw("'".$param1."'"));
        $join->on('arrival','=',DB::raw("'".$param2."'"));

    })
    ->where('bookings.room_type_id', '=', NULL)
    ->get();

và sau đó trả lại truy vấn của bạn

trả về kết quả $;


23

Mẫu truy vấn sql như thế này

LEFT JOIN bookings  
    ON rooms.id = bookings.room_type_id
    AND (bookings.arrival = ?
        OR bookings.departure = ?)

Tham gia Laravel với nhiều điều kiện

->leftJoin('bookings', function($join) use ($param1, $param2) {
    $join->on('rooms.id', '=', 'bookings.room_type_id');
    $join->on(function($query) use ($param1, $param2) {
        $query->on('bookings.arrival', '=', $param1);
        $query->orOn('departure', '=',$param2);
    });
})

11

Tôi đang sử dụng laravel5.2 và chúng tôi có thể thêm các phép nối với các tùy chọn khác nhau, bạn có thể sửa đổi theo yêu cầu của mình.

Option 1:    
    DB::table('users')
            ->join('contacts', function ($join) {
                $join->on('users.id', '=', 'contacts.user_id')->orOn(...);//you add more joins here
            })// and you add more joins here
        ->get();

Option 2:
    $users = DB::table('users')
        ->join('contacts', 'users.id', '=', 'contacts.user_id')
        ->join('orders', 'users.id', '=', 'orders.user_id')// you may add more joins
        ->select('users.*', 'contacts.phone', 'orders.price')
        ->get();

option 3:
    $users = DB::table('users')
        ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
        ->leftJoin('...', '...', '...', '...')// you may add more joins
        ->get();

3

Có sự khác biệt giữa các truy vấn thô và các lựa chọn tiêu chuẩn (giữa phương thức DB::rawDB::select).

Bạn có thể làm những gì bạn muốn bằng cách sử dụng một DB::selectvà chỉ cần thả vào ?trình giữ chỗ giống như bạn làm với các câu lệnh đã chuẩn bị sẵn (nó thực sự là những gì nó đang làm).

Một ví dụ nhỏ:

$results = DB::select('SELECT * FROM user WHERE username=?', ['jason']);

Tham số thứ hai là một mảng các giá trị sẽ được sử dụng để thay thế các trình giữ chỗ trong truy vấn từ trái sang phải.


Điều đó có nghĩa là các tham số được tự động thoát (lưu từ SQL injection)?
Dede

2
Vâng, nó chỉ là một trình bao bọc cho các tuyên bố chuẩn bị sẵn của PDO.
Jason Lewis,

Có cách nào để sử dụng kỹ thuật đó trong mệnh đề ON trong phép nối trái không? Xem câu hỏi của tôi tại đây . Tôi đã cố gắng đóng cửa bên trái của tôi để làm $join->on('winners.year','=',DB::select('?',array('2013'));nhưng không hiệu quả.
lập trình viên

đó không thực sự là cách hùng biện được thiết kế để hoạt động. bạn cũng có thể chỉ cần làm một DB :: thô () và làm cho nó chính mình
mydoglixu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.