쿼리 작성기 또는 Eloquent를 사용하여 추가 조건이있는 조인


94

Laravel Query Builder에서 JOIN 쿼리를 사용하여 조건을 추가하려고합니다.

<?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')
);

Raw Expressions를 사용할 수 있지만 SQL 삽입 지점이있을 것입니다. 쿼리 작성기로 다음을 시도했지만 생성 된 쿼리 (그리고 분명히 쿼리 결과)가 의도 한 것이 아닙니다.

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

다음은 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

보시다시피 쿼리 출력에는 구조가 없습니다 (특히 JOIN 범위 아래). JOIN에 조건을 추가 할 수 있나요?

Laravel의 Query Builder를 사용하여 동일한 쿼리를 작성하려면 어떻게해야합니까 (가능한 경우) Eloquent를 사용하는 것이 더 낫습니까, 아니면 DB :: select를 유지해야합니까?

답변:


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

laravel의 조인에 between 절을 추가 할 수 있는지 확실하지 않습니다.

메모:

  • DB::raw() Laravel은 따옴표를 다시 넣지 않도록 지시합니다.
  • 조인 메서드에 클로저를 전달하면 더 많은 조인 조건을 on()추가하고 AND조건 orOn()을 추가하며 OR조건 을 추가 할 수 있습니다.

답변 해주셔서 감사합니다. 안타깝게도 생성 된 쿼리는 이제 조인 조건이 and arrival >= ? and arrival <= ? and departure >= ? and departure <= ?대신 사용 되므로 약간 다릅니다 AND ( r.arrival between ? and ? OR r.departure between ? and ? )( OR절에 주의하십시오 ). 이것은 거기에 있으면 안되는 결과에 추가 행을 추가합니다. QB를 사용하여 조인에서 모든 유형의 조건을 생성하는 것은 불가능하다고 생각합니다.
dede

1
실제로 나는? ON 절에 추가되지 않습니다. ON의 해당 값은 매개 변수화되지 않으며 SQL 주입으로부터 보호되지 않습니다. 해결책을 찾기 위해 질문을 게시했습니다 .
prograhammer

3
이것은이 응답에서 무시 된 or 절이있는 원래 질문에 대답하지 않았습니다.
ionescho

완벽한 솔루션. 값을 사용할 때 DB :: raw를 사용하는 것을 잊지 마십시오. 그렇지 않으면 Laravel (최소한 5.6.29)에서 역 따옴표를 추가하고 목표를 "중단"하십시오.
Adrian Hernandez-Lopez

35

왼쪽 조인에서 이러한 대괄호를 복제 할 수 있습니다.

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(''));
})

그런 다음이 SO 게시물에 설명 된대로 나중에 "setBindings"를 사용하여 바인딩을 설정해야합니다 . 모델에서 사용되는 라 라벨의 원시 DB 쿼리에 매개 변수를 바인딩하는 방법은 무엇입니까?

예쁘지는 않지만 작동합니다.


32

매개 변수가있는 경우이를 수행 할 수 있습니다.

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

그런 다음 쿼리를 반환하십시오.

$ results 반환;


23

이와 같은 SQL 쿼리 샘플

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

Laravel은 여러 조건으로 결합

->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

laravel5.2를 사용하고 있으며 다른 옵션으로 조인을 추가 할 수 있으며 요구 사항에 따라 수정할 수 있습니다.

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

원시 쿼리와 표준 선택간에 차이가 있습니다 ( DB::rawDB::select메서드 간에 ).

를 사용하여 원하는 것을 할 수 있고 준비된 문장으로하는 것처럼 자리 표시 자에 DB::select간단히 놓을 수 있습니다 ?(실제로하는 일입니다).

작은 예 :

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

두 번째 매개 변수는 쿼리의 자리 표시자를 왼쪽에서 오른쪽으로 바꾸는 데 사용되는 값의 배열입니다.


매개 변수가 자동으로 이스케이프된다는 의미입니까 (SQL 주입에서 저장)?
dede

2
예, PDO 준비 명령문의 래퍼 일뿐입니다.
Jason Lewis

왼쪽 조인의 ON 절에서 해당 기술을 사용하는 방법이 있습니까? 여기에서 내 질문을 참조 하십시오 . 내 leftJoin 클로저 내부를 시도했지만 $join->on('winners.year','=',DB::select('?',array('2013'));작동하지 않았습니다.
prograhammer

그것은 실제로 작동하도록 설계된 방법이 아닙니다. DB :: raw ()를 사용하여 직접 만들 수도 있습니다
mydoglixu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.