Sorgu Oluşturucu veya Eloquent Kullanan Ek Koşullarla BİRLEŞME


94

Laravel Query Builder ile bir JOIN sorgusu kullanarak bir koşul eklemeye çalışıyorum.

<?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 İfadeleri kullanabileceğimi biliyorum ama sonra SQL enjeksiyon noktaları olacak. Sorgu Oluşturucu ile aşağıdakileri denedim, ancak oluşturulan sorgu (ve tabii ki, sorgu sonuçları) istediğim şey değil:

$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 tarafından üretilen sorgu şu şekildedir:

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

Gördüğünüz gibi, sorgu çıktısının yapısı yok (özellikle JOIN kapsamı altında). JOIN altında ek koşullar eklemek mümkün mü?

Laravel'in Sorgu Oluşturucusunu kullanarak aynı sorguyu nasıl oluşturabilirim (mümkünse) Eloquent kullanmak daha mı iyidir yoksa DB :: select ile kalmalı mı?

Yanıtlar:


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

Between cümlesinin laravel'deki birleşime eklenip eklenemeyeceğinden emin değilim.

Notlar:

  • DB::raw() Laravel'e alıntıları geri koymaması talimatını verir.
  • Birleştirme yöntemlerine bir kapanış geçirerek ona daha fazla birleştirme koşulu on()ekleyebilir, ANDkoşul ekleyecek ve koşul orOn()ekleyecektir OR.

Cevap için teşekkürler. Ne yazık ki, birleştirme koşulu artık and arrival >= ? and arrival <= ? and departure >= ? and departure <= ?bunun yerine sahip olduğu için oluşturulan sorgu biraz farklıdır AND ( r.arrival between ? and ? OR r.departure between ? and ? )(lütfen ORmaddeye dikkat edin ). Bu, orada olmaması gereken sonuçlara ek satırlar ekler. QB kullanarak birleştirme işleminde her tür koşulu oluşturmak mümkün değil sanırım.
dede

1
Aslında fark ettim ki? ON maddelerine eklenmez. ON'daki bu değerler parametreleştirilmez ve SQL enjeksiyonundan korunmaz. Çözümü bulmaya çalışan bir soru gönderdim .
prograhammer

3
bu, bu yanıtta göz ardı edilen bir veya cümlesi olan orijinal soruyu yanıtlamadı.
ionescho

Mükemmel çözüm. Bir değer kullanırken DB :: raw kullanmayı unutmayın, aksi takdirde Laravel (en azından 5.6.29'da) geri alıntılar ekler ve hedefi "bozar".
Adrian Hernandez-Lopez

35

Sol birleşimde bu parantezleri çoğaltabilirsiniz:

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

dır-dir

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

Daha sonra bağlamaları daha sonra bu SO yazısında açıklandığı gibi "setBindings" kullanarak ayarlamanız gerekir: Parametreler, Laravel'de bir modelde kullanılan ham bir DB sorgusuna nasıl bağlanır?

Güzel değil ama işe yarıyor.


32

Eğer bazı parametreleriniz varsa, bunu yapabilirsiniz.

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

ve sonra sorgunuzu iade edin

$ sonuçları döndür;


23

Bunun gibi sql sorgu örneği

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

Laravel birden çok koşulla birleştirin

->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 kullanıyorum ve farklı seçeneklerle birleşimler ekleyebiliriz, ihtiyacınıza göre değiştirebilirsiniz.

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

Ham sorgular ile standart seçimler arasında ( DB::rawve DB::selectyöntemleri arasında ) bir fark vardır.

A kullanarak DB::selectve basitçe ?yer tutucuyu tıpkı hazırlanmış ifadelerde yaptığınız gibi (aslında yaptığı şey budur) kullanarak yapabilirsiniz.

Küçük bir örnek:

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

İkinci parametre, sorgudaki yer tutucuları soldan sağa değiştirmek için kullanılacak bir değerler dizisidir.


Bu, parametrelerin otomatik olarak atlandığı anlamına mı geliyor (SQL enjeksiyonundan kaydetme)?
dede

2
Evet, sadece PDO tarafından hazırlanan ifadeler için bir paketleyici.
Jason Lewis

Bu tekniği bir sol birleşimdeki ON cümlesinde kullanmanın bir yolu var mı? Soruma burada bakın . Yapmak için solumun içinde denedim$join->on('winners.year','=',DB::select('?',array('2013')); ama işe yaramadı.
prograhammer

bu gerçekten çalışmak için tasarlanma şekli değildir. bir DB :: raw () yapıp kendiniz de yapabilirsiniz
mydoglixu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.