เข้าร่วมกับเงื่อนไขเพิ่มเติมโดยใช้ Query Builder หรือ Eloquent


94

ฉันกำลังพยายามเพิ่มเงื่อนไขโดยใช้คิวรี JOIN กับ Laravel Query Builder

<?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 ฉันได้ลองทำสิ่งต่อไปนี้กับ Query Builder แล้ว แต่แบบสอบถามที่สร้างขึ้น (และเห็นได้ชัดว่าผลการสืบค้น) ไม่ใช่สิ่งที่ฉันต้องการ:

$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 ได้หรือไม่?

ฉันจะสร้างแบบสอบถามเดียวกันโดยใช้ Query Builder ของ Laravel ได้อย่างไร (ถ้าเป็นไปได้) จะดีกว่าถ้าใช้ 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();

ไม่แน่ใจว่าระหว่าง clause สามารถเพิ่มใน join in laravel ได้หรือไม่

หมายเหตุ:

  • 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
สิ่งนี้ไม่ได้ตอบคำถามเดิมที่มีหรืออนุประโยคที่ถูกละเว้นในคำตอบนี้
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(''));
})

จากนั้นคุณจะต้องตั้งค่าการเชื่อมในภายหลังโดยใช้ "setBindings" ตามที่อธิบายไว้ในโพสต์ SO นี้: จะผูกพารามิเตอร์กับแบบสอบถาม DB ดิบใน Laravel ที่ใช้กับโมเดลได้อย่างไร

มันไม่สวย แต่ใช้งานได้


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

แล้วส่งกลับคำค้นหาของคุณ

ส่งคืนผลลัพธ์ $;


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::rawและDB::selectวิธีการ)

คุณสามารถทำในสิ่งที่คุณต้องการโดยใช้DB::selectและเพียงแค่วางลงใน?ตัวยึดตำแหน่งเหมือนกับที่คุณทำกับข้อความที่เตรียมไว้ (มันคือสิ่งที่ทำอยู่)

ตัวอย่างเล็ก ๆ :

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

พารามิเตอร์ที่สองคืออาร์เรย์ของค่าที่จะใช้เพื่อแทนที่ตัวยึดตำแหน่งในแบบสอบถามจากซ้ายไปขวา


นั่นหมายความว่าพารามิเตอร์จะถูกหลีกเลี่ยงโดยอัตโนมัติ (บันทึกจากการแทรก SQL) หรือไม่
dede

2
ใช่มันเป็นเพียงกระดาษห่อหุ้มสำหรับงบที่เตรียมไว้ของ PDO
Jason Lewis

มีวิธีใดบ้างที่จะใช้เทคนิคนั้นในส่วนคำสั่ง ON ในการรวมด้านซ้าย? ดูคำถามของฉันที่นี่ ฉันพยายามที่ด้านซ้ายของฉันเข้าร่วมการปิดเพื่อทำ$join->on('winners.year','=',DB::select('?',array('2013'));แต่ไม่ได้ผล
prograhammer

นั่นไม่ใช่วิธีการออกแบบมาเพื่อใช้งานที่เฉียบแหลม คุณอาจทำ DB :: raw () และสร้างด้วยตัวเอง
mydoglixu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.