Laravel: Query Builder


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Mục lục bài viết: 


Giới thiệu

Trình tạo truy vấn (Query builder) cơ sở dữ liệu của Laravel cung cấp một cách thức tiếp cận thân thiện để tạo và chạy các truy vấn cơ sở dữ liệu. Nó có thể được sử dụng để thực hiện hầu hết các hoạt động cơ sở dữ liệu trong ứng dụng của bạn và hoạt động hoàn hảo với tất cả các hệ thống cơ sở dữ liệu được hỗ trợ của Laravel.

Trình tạo truy vấn Laravel sử dụng liên kết tham số PDO để bảo vệ ứng dụng của bạn chống lại các cuộc tấn công chèn SQL (SQL injection). Bạn không cần phải làm sạch hoặc làm sạch các chuỗi được chuyển đến trình tạo truy vấn dưới dạng các ràng buộc truy vấn.

PDO không hỗ trợ tên cột ràng buộc. Do đó, bạn không bao giờ được phép cho phép người dùng nhập tên cột mà truy vấn của bạn tham chiếu, bao gồm cả các cột "order by".

Chạy truy vấn cơ sở dữ liệu

Lấy tất cả các hàng từ một bảng

Bạn có thể sử dụng phương thức table được cung cấp bởi facade DB để bắt đầu truy vấn. Phương thức table trả về một đối tượng query builder cho bảng nhất định, cho phép bạn đưa nhiều ràng buộc vào truy vấn và sau đó lấy lại kết quả của truy vấn bằng cách sử dụng phương thức get.

Ví dụ:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;

class UserController extends Controller
{
    public function index()
    {
        $users = DB::table('users')->get();

        return view('user.index', ['users' => $users]);
    }
}

Phương thức get trả về một đối tượng Illuminate\Support\Collection có chứa các kết quả của truy vấn trong đó mỗi kết quả là một thể hiện của đối tượng PHP stdClass. Bạn có thể truy cập giá trị của từng cột bằng cách truy cập cột đó như một thuộc tính của đối tượng.

Ví dụ:

use Illuminate\Support\Facades\DB;

$users = DB::table('users')->get();

foreach ($users as $user) {
    echo $user->name;
}

Collection Laravel cung cấp nhiều phương thức cực kỳ mạnh mẽ để ánh xạ và thu nhỏ dữ liệu. Để biết thêm thông tin về collection, hãy xem tài liệu về collection.

Lấy một hàng/cột đơn từ bảng

Nếu bạn chỉ cần truy xuất một hàng từ bảng cơ sở dữ liệu, bạn có thể sử dụng phương thức first. Phương thức này sẽ trả về một đối tượng stdClass:

$user = DB::table('users')->where('name', 'John')->first();

return $user->email;

Nếu bạn không cần toàn bộ dữ liệu trên một hàng, bạn có thể trích xuất một giá trị từ một bản ghi bằng cách dùng phương thức value. Phương thức này sẽ trả về giá trị của cột tương ứng:

$email = DB::table('users')->where('name', 'John')->value('email');

Để truy xuất một hàng theo giá trị của cột id bạn hãy sử dụng phương thức find:

$user = DB::table('users')->find(3);

Truy xuất danh sách giá trị cột

Nếu bạn muốn truy xuất các giá trị của một cột, bạn có thể sử dụng phương thức pluck:

use Illuminate\Support\Facades\DB;

$titles = DB::table('users')->pluck('title');

foreach ($titles as $title) {
    echo $title;
}

Bạn có thể chỉ định cột mà tập kết quả sẽ sử dụng làm khóa (key) của nó bằng cách cung cấp đối số thứ hai cho phương thức pluck:

$titles = DB::table('users')->pluck('title', 'name');

foreach ($titles as $name => $title) {
    echo $title;
}

Phân chia kết quả

Nếu bạn cần làm việc với hàng nghìn bản ghi cơ sở dữ liệu, hãy xem xét sử dụng phương thức chunk. chunk sẽ truy xuất một phần nhỏ kết quả tại một thời điểm và đưa mỗi phần vào closure (hàm callback) để xử lý. Ví dụ sau đây truy xuất toàn bộ dữ liệu của bảng users nhưng với 100 bản ghi tại một thời điểm:

use Illuminate\Support\Facades\DB;

DB::table('users')->orderBy('id')->chunk(100, function ($users) {
    foreach ($users as $user) {
        //
    }
});

Bạn có thể ngừng xử lý các phần tiếp theo bằng cách trả về false như sau:

DB::table('users')->orderBy('id')->chunk(100, function ($users) {
    // Xử lý bản ghi

    return false;
});

Nếu bạn đang cập nhật bản ghi cơ sở dữ liệu trong khi phân chia kết quả, thì kết quả phân chia của bạn có thể thay đổi theo những cách không mong muốn. Nếu bạn dự định cập nhật các bản ghi đã truy xuất trong khi phân chia, thì cách tốt nhất là bạn nên sử dụng phương thức chunkById để thay thế. Phương thức này sẽ tự động phân trang các kết quả dựa trên khóa chính của bản ghi:

DB::table('users')->where('active', false)
    ->chunkById(100, function ($users) {
        foreach ($users as $user) {
            DB::table('users')
                ->where('id', $user->id)
                ->update(['active' => true]);
        }
    });

Khi cập nhật hoặc xóa các bản ghi bên trong lệnh callback của chunk, thì bất kỳ thay đổi nào đối với khóa chính hoặc khóa ngoại có thể ảnh hưởng đến truy vấn chunk. Điều này có thể dẫn đến việc các bản ghi không được đưa vào các kết quả phân chia.

Thống kê, tập hợp

Query builder cũng cung cấp một loạt các phương thức để lấy giá trị tổng hợp như countmaxminavg, và sum. Bạn có thể gọi bất kỳ phương thức nào sau đây sau khi tạo truy vấn của mình:

use Illuminate\Support\Facades\DB;

$users = DB::table('users')->count();

$price = DB::table('orders')->max('price');

Tất nhiên, bạn có thể kết hợp các phương thức này với các mệnh đề khác để tinh chỉnh cách tính giá trị tổng hợp của bạn:

$price = DB::table('orders')
                ->where('finalized', 1)
                ->avg('price');

Xác định xem bản ghi có tồn tại không

Thay vì sử dụng phương thức count để xác định xem có tồn tại bất kỳ bản ghi nào phù hợp với các ràng buộc của truy vấn hay không, bạn có thể sử dụng các phương thức exists và doesntExist:

if (DB::table('orders')->where('finalized', 1)->exists()) {
    // ...
}

if (DB::table('orders')->where('finalized', 1)->doesntExist()) {
    // ...
}

Câu lệnh select

Chỉ định một mệnh đề select

Không phải lúc nào bạn cũng có thể muốn chọn tất cả các cột từ bảng cơ sở dữ liệu. Sử dụng phương thức select bạn có thể chọn được những cột mong muốn một cách dễ dàng:

use Illuminate\Support\Facades\DB;

$users = DB::table('users')
            ->select('name', 'email as user_email')
            ->get();

Phương thức distinct cho phép bạn chỉ lấy một kết quả trong các kết quả giống nhau:

$users = DB::table('users')->distinct()->get();

Nếu bạn đã có một query builder rồi và bạn muốn thêm một cột vào kết quả thì bạn có thể sử dụng phương thức addSelect:

$query = DB::table('users')->select('name');

$users = $query->addSelect('age')->get();

Biểu thức raw

Đôi khi bạn có thể cần phải chèn một chuỗi tùy chỉnh vào một truy vấn. Để làm được điều này thì bạn có thể sử dụng phương thức raw:

$users = DB::table('users')
             ->select(DB::raw('count(*) as user_count, status'))
             ->where('status', '<>', 1)
             ->groupBy('status')
             ->get();

Các câu lệnh raw sẽ được đưa vào truy vấn dưới dạng chuỗi, vì vậy bạn phải cực kỳ cẩn thận để tránh tạo lỗ hổng SQL injection.

Các phương thức raw

Thay vì sử dụng phương thức raw thì bạn cũng có thể sử dụng các phương thức sau để chèn một biểu thức thô vào các phần khác nhau của truy vấn của mình. Nhưng bạn cần lưu ý là Laravel không thể đảm bảo rằng bất kỳ truy vấn nào sử dụng biểu thức thô đều được bảo vệ khỏi các lỗ hổng SQL injection.

selectRaw

Phương thức selectRaw có thể được sử dụng thay cho addSelect(DB::raw(...)). Phương thức này chấp nhận một mảng ràng buộc tùy chọn làm đối số thứ hai của nó:

$orders = DB::table('orders')
                ->selectRaw('price * ? as price_with_tax', [1.0825])
                ->get();

whereRaw/orWhereRaw

Các phương thức whereRaw và orWhereRaw có thể được sử dụng để đưa mệnh đề "where" thô vào truy vấn của bạn. Các phương thức này chấp nhận một mảng ràng buộc tùy chọn làm đối số thứ hai:

$orders = DB::table('orders')
                ->whereRaw('price > IF(state = "TX", ?, 100)', [200])
                ->get();

havingRaw/orHavingRaw

Các phương thức havingRaw và orHavingRaw có thể được sử dụng để cung cấp một chuỗi thô làm giá trị của mệnh đề "having". Các phương thức này chấp nhận một mảng ràng buộc tùy chọn làm đối số thứ hai của chúng:

$orders = DB::table('orders')
                ->select('department', DB::raw('SUM(price) as total_sales'))
                ->groupBy('department')
                ->havingRaw('SUM(price) > ?', [2500])
                ->get();

orderByRaw

Phương thức orderByRaw có thể được sử dụng để cung cấp một chuỗi thô là giá trị của mệnh đề "order by":

$orders = DB::table('orders')
                ->orderByRaw('updated_at - created_at DESC')
                ->get();

groupByRaw

Phương thức groupByRaw có thể được sử dụng để cung cấp một chuỗi thôi là giá trị của mệnh đề group by:

$orders = DB::table('orders')
                ->select('city', 'state')
                ->groupByRaw('city, state')
                ->get();

Join

Mệnh đề inner join

Query builder cũng có thể được sử dụng để thêm các mệnh đề join vào các truy vấn của bạn. Bạn có thể sử dụng phương thức join trong đó đối số đầu tiên được truyền cho phương thức join là tên của bảng mà bạn cần join, trong khi các đối số còn lại chỉ định các ràng buộc cột join. Bạn thậm chí có thể kết hợp nhiều bảng trong một truy vấn:

use Illuminate\Support\Facades\DB;

$users = DB::table('users')
            ->join('contacts', 'users.id', '=', 'contacts.user_id')
            ->join('orders', 'users.id', '=', 'orders.user_id')
            ->select('users.*', 'contacts.phone', 'orders.price')
            ->get();

Mệnh đề left join/right join

Nếu bạn muốn thực hiện "left join" hoặc "right join" thì bạn hãy sử dụng các phương thức leftJoin hoặc rightJoin. Các phương thức này có cùng cú pháp với phương thức join:

$users = DB::table('users')
            ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
            ->get();

$users = DB::table('users')
            ->rightJoin('posts', 'users.id', '=', 'posts.user_id')
            ->get();

Mệnh đề cross join

Bạn có thể sử dụng phương thức crossJoin để thực hiện "cross join":

$sizes = DB::table('sizes')
            ->crossJoin('colors')
            ->get();

Các mệnh đề join nâng cao

Bạn cũng có thể chỉ định các mệnh đề join nâng cao hơn. Để bắt đầu ta sẽ truyền một closure làm đối số thứ hai cho phương thức join.

Ví dụ:

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

Nếu bạn muốn sử dụng mệnh đề "where" trên các phép nối của mình, bạn có thể sử dụng các phương thức where và orWhere:

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

Kết hợp truy vấn con

Bạn có thể sử dụng các phương thức joinSubleftJoinSub và rightJoinSub để join một truy vấn với một truy vấn con. Mỗi phương thức này sẽ nhận ba đối số: truy vấn con, bí danh bảng của nó và một closure để định nghĩa các cột liên quan. Ví dụ sau sẽ truy xuất một tập hợp người dùng trong đó mỗi bản ghi người dùng cũng chứa timestamps created_at của bài đăng blog được xuất bản gần đây nhất của người dùng:

$latestPosts = DB::table('posts')
                   ->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
                   ->where('is_published', true)
                   ->groupBy('user_id');

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

Union

Query builder cũng cung cấp một phương thức thuận tiện để "kết hợp" hai hoặc nhiều truy vấn lại với nhau. Ví dụ: bạn có thể tạo một truy vấn ban đầu và sử dụng phương thức union để kết hợp nó với các truy vấn khác:

use Illuminate\Support\Facades\DB;

$first = DB::table('users')
            ->whereNull('first_name');

$users = DB::table('users')
            ->whereNull('last_name')
            ->union($first)
            ->get();

Ngoài phương thức union ra thì ta còn phương thức unionAll. Các truy vấn được kết hợp bằng phương thức unionAll sẽ không bị xóa các kết quả trùng lặp. unionAll có cú pháp giống với union.

Các mệnh đề where cơ bản

Mệnh đề where

Phương thức where cơ bản nhất yêu cầu ba đối số. Đối số đầu tiên là tên của cột. Đối số thứ hai là một toán tử, có thể là bất kỳ toán tử nào được hỗ trợ của cơ sở dữ liệu. Đối số thứ ba là giá trị để so sánh với giá trị của cột.

Ví dụ: truy vấn sau đây truy xuất người dùng trong đó giá trị của cột votes bằng 100 và giá trị của cột age lớn hơn 35:

$users = DB::table('users')
                ->where('votes', '=', 100)
                ->where('age', '>', 35)
                ->get();

Để thuận tiện, nếu bạn muốn rằng một cột là = một giá trị nhất định, bạn có thể chuyển giá trị làm đối số thứ hai như sau:

$users = DB::table('users')->where('votes', 100)->get(); //tương đương với where votes = 100

Như đã nói đến ở trên, bạn có thể sử dụng bất kỳ toán tử nào được hỗ trợ bởi hệ thống cơ sở dữ liệu của bạn:

$users = DB::table('users')
                ->where('votes', '>=', 100)
                ->get();

$users = DB::table('users')
                ->where('votes', '<>', 100)
                ->get();

$users = DB::table('users')
                ->where('name', 'like', 'T%')
                ->get();

Bạn cũng có thể truyền một mảng các điều kiện cho hàm where, trong đó mỗi phần tử của mảng phải là một mảng chứa ba đối số thường được truyền cho phương thức where:

$users = DB::table('users')->where([
    ['status', '=', '1'],
    ['subscribed', '<>', '1'],
])->get();

Hàm orWhere

Bạn có thể sử dụng phương thức orWhere để nối một mệnh đề với truy vấn bằng toán tử or. Cú pháp của orWhere tương tự như cú pháp của where:

$users = DB::table('users')
                    ->where('votes', '>', 100)
                    ->orWhere('name', 'John')
                    ->get();

Nếu bạn cần nhóm một điều kiện "or" trong cặp ngoặc tròn thì bạn có thể truyền một closure làm đối số đầu tiên cho orWhere:

$users = DB::table('users')
            ->where('votes', '>', 100)
            ->orWhere(function($query) {
                $query->where('name', 'Abigail')
                      ->where('votes', '>', 50);
            })
            ->get();

Ví dụ trên sẽ tạo ra câu lệnh SQL tương ứng sau:

select * from users where votes > 100 or (name = 'Abigail' and votes > 50)

Bạn nên luôn nhóm các lời gọi orWhere để tránh hành vi không mong muốn khi áp dụng các quy tắc chung (global).

Mệnh đề where JSON

Laravel cũng hỗ trợ truy vấn các cột JSON. Để truy vấn một cột JSON ta sử dụng toán tử ->:

$users = DB::table('users')
                ->where('preferences->dining->meal', 'salad')
                ->get();

Bạn có thể sử dụng phương thức whereJsonContains để truy vấn mảng JSON. Tính năng này không được cơ sở dữ liệu SQLite hỗ trợ:

$users = DB::table('users')
                ->whereJsonContains('options->languages', 'en')
                ->get();

Nếu ứng dụng của bạn sử dụng cơ sở dữ liệu MySQL hoặc PostgreSQL, bạn có thể chuyển một mảng giá trị cho phương thức whereJsonContains như sau:

$users = DB::table('users')
                ->whereJsonContains('options->languages', ['en', 'de'])
                ->get();

Bạn có thể sử dụng whereJsonLength để truy vấn mảng JSON theo độ dài của chúng:

$users = DB::table('users')
                ->whereJsonLength('options->languages', 0)
                ->get();

$users = DB::table('users')
                ->whereJsonLength('options->languages', '>', 1)
                ->get();

Các mệnh where khác

whereBetween / orWhereBetween

Phương thức whereBetween dùng để kiểm tra xem giá trị của cột có nằm giữa hai giá trị không:

$users = DB::table('users')
           ->whereBetween('votes', [1, 100])
           ->get();

whereNotBetween / orWhereNotBetween

Phương thức whereNotBetween dùng để kiểm tra xem giá trị của cột có nằm ngoài hai giá trị không:

$users = DB::table('users')
                    ->whereNotBetween('votes', [1, 100])
                    ->get();

whereIn / whereNotIn / orWhereIn / orWhereNotIn

Phương thức whereIn dùng để kiểm tra xem giá trị của cột có là một trong các giá trị trong mảng không:

$users = DB::table('users')
                    ->whereIn('id', [1, 2, 3])
                    ->get();

Phương thức whereNotIn dùng để kiểm tra xem giá trị của cột có không là một trong các giá trị trong mảng không:

$users = DB::table('users')
                    ->whereNotIn('id', [1, 2, 3])
                    ->get();

Nếu bạn đang thêm một mảng lớn các liên kết số nguyên vào truy vấn của mình, thì các phương thức whereIntegerInRaw hoặc whereIntegerNotInRaw có thể được sử dụng để giảm đáng kể mức sử dụng bộ nhớ của bạn.

whereNull / whereNotNull / orWhereNull / orWhereNotNull

Phương thức whereNull dùng để kiểm tra xem giá trị của cột có NULL không:

$users = DB::table('users')
                ->whereNull('updated_at')
                ->get();

Phương thức whereNotNull dùng để kiểm tra xem giá trị của cột có không phải là NULL không:

$users = DB::table('users')
                ->whereNotNull('updated_at')
                ->get();

whereDate / whereMonth / whereDay / whereYear / whereTime

Phương thức whereDate có thể được sử dụng để so sánh cột với giá trị năm tháng ngày đưa ra:

$users = DB::table('users')
                ->whereDate('created_at', '2016-12-31')
                ->get();

Phương thức whereMonth có thể được sử dụng để so sánh cột với giá trị tháng đưa ra:

$users = DB::table('users')
                ->whereMonth('created_at', '12')
                ->get();

Phương thức whereDay có thể được sử dụng để so sánh cột với giá trị ngày đưa ra:

$users = DB::table('users')
                ->whereDay('created_at', '31')
                ->get();

Phương thức whereYear có thể được sử dụng để so sánh cột với giá trị năm đưa ra:

$users = DB::table('users')
                ->whereYear('created_at', '2016')
                ->get();

Phương thức whereTime có thể được sử dụng để so sánh cột với giá trị giờ phút giây đưa ra:

$users = DB::table('users')
                ->whereTime('created_at', '=', '11:20:45')
                ->get();

whereColumn / orWhereColumn

Phương thức whereColumn có thể được sử dụng để so sánh hai cột:

$users = DB::table('users')
                ->whereColumn('first_name', 'last_name')
                ->get();

Bạn cũng có thể truyền một toán tử so sánh cho phương thức whereColumn:

$users = DB::table('users')
                ->whereColumn('updated_at', '>', 'created_at')
                ->get();

Bạn cũng có thể truyền một mảng so sánh cột cho phương thức whereColumn:

$users = DB::table('users')
                ->whereColumn([
                    ['first_name', '=', 'last_name'],
                    ['updated_at', '>', 'created_at'],
                ])->get();

Nhóm logic

Đôi khi bạn có thể cần phải nhóm một số mệnh đề "where" để đạt được nhóm logic mong muốn cho câu lệnh truy vấn. Trên thực tế, bạn nên nhóm các lệnh gọi đến phương thức orWhere trong cặp ngoặc tròn sử dụng closure để tránh hành vi truy vấn không mong muốn. Để thực hiện điều này, bạn có thể truyền một closure cho phương thức where:

$users = DB::table('users')
           ->where('name', '=', 'John')
           ->where(function ($query) {
               $query->where('votes', '>', 100)
                     ->orWhere('title', '=', 'Admin');
           })
           ->get();

Ví dụ trên sẽ tạo ra câu lệnh SQL tương ứng sau:

select * from users where name = 'John' and (votes > 100 or title = 'Admin')

Bạn nên luôn closure hàm orWhere để tránh hành vi không mong muốn.

Các mệnh đề where nâng cao

Mệnh đề where exists

Phương thức whereExists dùng để kiểm tra xem có tồn tại bản ghi mong muốn không, nó tương đương với mệnh đề "where exists" trong SQLwhereExists chấp nhận một closure:

$users = DB::table('users')
           ->whereExists(function ($query) {
               $query->select(DB::raw(1))
                     ->from('orders')
                     ->whereColumn('orders.user_id', 'users.id');
           })
           ->get();

Truy vấn trên sẽ tạo ra câu lệnh SQL tương ứng sau:

select * from users
where exists (
    select 1
    from orders
    where orders.user_id = users.id
)

Mệnh đề where chứa truy vấn con

Đôi khi bạn có thể cần phải xây dựng một mệnh đề "where" để so sánh kết quả của một truy vấn con với một giá trị nhất định. Bạn có thể thực hiện điều này bằng cách truyền một closure và một giá trị cho phương thức where.

Ví dụ: truy vấn sau sẽ truy xuất tất cả người dùng có "tư cách thành viên" gần đây của một kiểu đã cho:

use App\Models\User;

$users = User::where(function ($query) {
    $query->select('type')
        ->from('membership')
        ->whereColumn('membership.user_id', 'users.id')
        ->orderByDesc('membership.start_date')
        ->limit(1);
}, 'Pro')->get();

Hoặc, bạn có thể cần phải xây dựng một mệnh đề "where" để so sánh một cột với kết quả của một truy vấn con. Bạn có thể thực hiện điều này bằng cách chuyển một cột, toán tử và closure cho phương thức where. Ví dụ: truy vấn sau sẽ truy xuất tất cả các bản ghi thu nhập trong đó số tiền nhỏ hơn mức trung bình:

use App\Models\Income;

$incomes = Income::where('amount', '<', function ($query) {
    $query->selectRaw('avg(i.amount)')->from('incomes as i');
})->get();

Order By, Group By, Limit và Offset

Order By

Phương thức orderBy

Phương thức orderBy (Order By trong SQL) cho phép bạn sắp xếp các kết quả của truy vấn bởi một cột nhất định. Đối số đầu tiên được phương thức orderBy chấp nhận phải là cột bạn muốn sắp xếp, còn đối số thứ hai xác định hướng sắp xếp và có thể là asc hoặc desc:

$users = DB::table('users')
                ->orderBy('name', 'desc')
                ->get();

Để sắp xếp theo nhiều cột bạn chỉ cần gọi orderBy nhiều lần nếu cần:

$users = DB::table('users')
                ->orderBy('name', 'desc')
                ->orderBy('email', 'asc')
                ->get();

Phương thức latest và oldest

Các phương thức latest và oldest cho phép bạn dễ dàng sắp xếp kết quả theo ngày. Theo mặc định, kết quả sẽ được sắp xếp theo cột created_at của bảng. Hoặc, bạn có thể chuyển tên cột mà bạn muốn sắp xếp theo:

$user = DB::table('users')
                ->latest()
                ->first();

Order By ngẫu nhiên

Phương thức inRandomOrder có thể được sử dụng để sắp xếp các kết quả truy vấn một cách ngẫu nhiên. Ví dụ: bạn có thể sử dụng phương thức này để lấy một user ngẫu nhiên như sau:

$randomUser = DB::table('users')
                ->inRandomOrder()
                ->first();

Loại bỏ các mệnh đề Order By hiện có

Phương thức reorder sẽ loại bỏ tất cả các mệnh đề "order by" mà trước đây đã được áp dụng cho các truy vấn:

$query = DB::table('users')->orderBy('name');

$unorderedUsers = $query->reorder()->get();

Bạn có thể truyền một cột và hướng (asc hay desc) khi gọi phương thức reorder để loại bỏ tất cả các mệnh đề "order by" hiện có và áp dụng việc sắp xếp hoàn toàn mới cho truy vấn:

$query = DB::table('users')->orderBy('name');

$usersOrderedByEmail = $query->reorder('email', 'desc')->get();

Group By

Phương thức groupBy và having

Các phương thức groupBy và having (Group By và Having trong SQL) có thể được sử dụng để nhóm các kết quả truy vấn:

$users = DB::table('users')
                ->groupBy('account_id')
                ->having('account_id', '>', 100)
                ->get();

Bạn có thể truyền nhiều đối số cho groupBy để nhóm theo nhiều cột:

$users = DB::table('users')
                ->groupBy('first_name', 'status')
                ->having('account_id', '>', 100)
                ->get();

Để xây dựng các cậu lệnh truy vấn với having nâng cao hơn bạn có thể xem phương thức havingRaw.

Limit và Offset

Các phương thức skip và take

Bạn có thể sử dụng các phương thức skip và take để giới hạn số lượng kết quả trả về từ truy vấn hoặc bỏ qua một số kết quả nhất định trong truy vấn:

$users = DB::table('users')->skip(10)->take(5)->get();

Ngoài ra, bạn có thể sử dụng các phương thức limit và offset. Các phương thức này tương đương về mặt chức năng với các phương thức take và skip:

$users = DB::table('users')
                ->offset(10)
                ->limit(5)
                ->get();

Phương thức when

Đôi khi bạn có thể muốn các mệnh đề truy vấn nhất định áp dụng cho một truy vấn dựa trên một điều kiện khác. Ví dụ: bạn có thể chỉ muốn áp dụng một câu lệnh where nếu một giá trị đầu vào nhất định có trong yêu cầu đến HTTP. Bạn có thể thực hiện điều này bằng cách sử dụng phương thức when:

$role = $request->input('role');

$users = DB::table('users')
                ->when($role, function ($query, $role) {
                    return $query->where('role_id', $role);
                })
                ->get();

Phương thức when chỉ thực hiện closure khi đối số đầu tiên là true. Nếu đối số đầu tiên là false, thì closure sẽ không được thực hiện. Vì vậy, trong ví dụ trên, closure được cung cấp cho phương thức when sẽ chỉ được gọi nếu trường role có trong yêu cầu đến và có giá trị là true.

Bạn có thể truyền một closuere khác làm đối số thứ ba cho phương thức when. Closure này sẽ chỉ thực thi nếu đối số đầu tiên mang giá trị là false. Để minh họa cách sử dụng tính năng này, ta sẽ sử dụng nó để định cấu hình thứ tự mặc định của một truy vấn:

$sortByVotes = $request->input('sort_by_votes');

$users = DB::table('users')
                ->when($sortByVotes, function ($query, $sortByVotes) {
                    return $query->orderBy('votes');
                }, function ($query) {
                    return $query->orderBy('name');
                })
                ->get();

Phương thức insert

Query Builder cũng cung cấp phương thức insert có thể được sử dụng để chèn các bản ghi vào bảng cơ sở dữ liệu. Phương thức insert chấp nhận một loạt các tên cột và các giá trị:

DB::table('users')->insert([
    'email' => 'kayla@example.com',
    'votes' => 0
]);

Ta có thể chèn nhiều bản ghi cùng một lúc bằng cách truyền một mảng các mảng. Mỗi mảng đại diện cho một bản ghi cần được chèn vào bảng:

DB::table('users')->insert([
    ['email' => 'picard@example.com', 'votes' => 0],
    ['email' => 'janeway@example.com', 'votes' => 0],
]);

Phương thức insertOrIgnore sẽ bỏ qua lỗi bản ghi trùng lặp trong khi chèn các bản ghi vào cơ sở dữ liệu:

DB::table('users')->insertOrIgnore([
    ['id' => 1, 'email' => 'sisko@example.com'],
    ['id' => 2, 'email' => 'archer@example.com'],
]);

ID tự động tăng

Nếu bảng có id tăng tự động thì ta sử dụng phương thức insertGetId để chèn bản ghi và sau đó truy xuất ID:

$id = DB::table('users')->insertGetId(
    ['email' => 'john@example.com', 'votes' => 0]
);
 

Khi sử dụng PostgreSQL, phương thức insertGetId sẽ đặt tên cho cột tự động tăng dần id. Nếu bạn muốn truy xuất ID từ một "chuỗi" khác, bạn có thể truyền tên cột làm tham số thứ hai cho phương thức insertGetId.

Phương thức upsert

Phương thức upsert sẽ chèn bản ghi mà không tồn tại và cập nhật bản ghi đã tồn tại với các giá trị mới mà bạn có thể chỉ định. Đối số đầu tiên của phương thức bao gồm các giá trị để chèn hoặc cập nhật, trong khi đối số thứ hai liệt kê (các) cột xác định duy nhất các bản ghi trong bảng được liên kết. Đối số thứ ba và là cuối cùng của phương thức là một mảng các cột cần được cập nhật nếu bản ghi phù hợp đã tồn tại trong cơ sở dữ liệu:

DB::table('flights')->upsert([
    ['departure' => 'Oakland', 'destination' => 'San Diego', 'price' => 99],
    ['departure' => 'Chicago', 'destination' => 'New York', 'price' => 150]
], ['departure', 'destination'], ['price']);

Trong ví dụ trên, Laravel sẽ cố gắng chèn hai bản ghi. Nếu một bản ghi đã tồn tại với các giá trị cột tương tự nhau là departure và destination, thì Laravel sẽ cập nhật cột price của bản ghi đó.

Tất cả các cơ sở dữ liệu ngoại trừ SQL Server yêu cầu các cột trong đối số thứ hai của phương thức upsert phải có chỉ mục "khóa chính - PK" hoặc "duy nhất - Unique".

Phương thức update

Ngoài việc chèn các bản ghi vào cơ sở dữ liệu, trình tạo truy vấn cũng có thể cập nhật các bản ghi hiện có bằng phương thức update. Phương thức update giống như phương thức insert, nó chấp nhận một loạt các cặp cột và giá trị chỉ ra các cột được cập nhật. Bạn có thể ràng buộc phương thức update với phương thức where:

$affected = DB::table('users')
              ->where('id', 1)
              ->update(['votes' => 1]);

Phương thức updateOrInsert

Đôi khi bạn có thể muốn cập nhật một bản ghi hiện có trong cơ sở dữ liệu hoặc tạo nó nếu không có bản ghi phù hợp nào tồn tại. Trong trường hợp này ta có thể sử dụng phương thức updateOrInsertupdateOrInsert chấp nhận hai đối số: một mảng các điều kiện để tìm ra bản ghi, và một mảng của các cặp cột và giá trị chỉ ra các cột được cập nhật.

Phương thức updateOrInsert sẽ cố gắng xác định vị trí một bản ghi trong cơ sở dữ liệu phù hợp sử dụng cặp cột và giá trị của đối số đầu tiên. Nếu bản ghi tồn tại thì nó sẽ được cập nhật với các giá trị trong đối số thứ hai. Nếu không thể tìm thấy bản ghi thì bản ghi mới sẽ được chèn với các thuộc tính đã hợp nhất của cả hai đối số:

DB::table('users')
    ->updateOrInsert(
        ['email' => 'john@example.com', 'name' => 'John'],
        ['votes' => '2']
    );

Cập nhật các cột JSON

Khi cập nhật một cột JSON, bạn nên sử dụng cú pháp -> để cập nhật khóa thích hợp trong đối tượng JSON. Thao tác này được hỗ trợ trên MySQL 5.7+ và PostgreSQL 9.5+:

$affected = DB::table('users')
              ->where('id', 1)
              ->update(['options->enabled' => true]);

Phương thức increment() và decrement()

Trình tạo truy vấn cũng cung cấp các phương thức thuận tiện để tăng hoặc giảm giá trị của một cột nhất định. Cả hai phương thức này đều chấp nhận ít nhất một đối số: cột cần sửa đổi. Đối số thứ hai có thể được cung cấp để chỉ định số lượng cột sẽ được tăng hoặc giảm:

DB::table('users')->increment('votes');

DB::table('users')->increment('votes', 5);

DB::table('users')->decrement('votes');

DB::table('users')->decrement('votes', 5);

Bạn cũng có thể chỉ định các cột bổ sung để cập nhật trong quá trình hoạt động:

DB::table('users')->increment('votes', 1, ['name' => 'John']);

Xóa dữ liệu bảng

Phương thức delete của trình tạo truy vấn có thể được sử dụng để xóa các bản ghi khỏi bảng. Bạn có thể ràng buộc phương thức delete bằng cách đặt phương thức where trước phương thức delete:

DB::table('users')->delete();

DB::table('users')->where('votes', '>', 100)->delete();

Nếu bạn muốn xóa dữ liệu trên toàn bộ bảng thì ta dùng phương thức truncate, phương thức này sẽ xóa tất cả các bản ghi khỏi bảng và đặt lại ID tự động tăng dần về 0:

DB::table('users')->truncate();

Xóa dữ liệu (truncate) bảng trong PostgreSQL

Khi xóa dữ liệu trong PostgreSQL thì hành vi CASCADE sẽ được áp dụng, điều này có nghĩa là tất cả các bản ghi liên quan đến khóa ngoại trong các bảng khác cũng sẽ bị xóa.

Khóa bi quan (Pessimistic Locking)

Trình tạo truy vấn cũng có một vài chức năng để giúp bạn có được "khóa bi quan" khi thực hiện các câu lệnh select. Để thực hiện một câu lệnh với "khóa chia sẻ - shared lock", bạn có thể gọi phương thức sharedLock. Khóa chia sẻ sẽ ngăn các hàng đã chọn không được sửa đổi cho đến khi giao dịch của ta hoàn thành (committed):

DB::table('users')
        ->where('votes', '>', 100)
        ->sharedLock()
        ->get();

Ngoài ra, bạn có thể sử dụng phương thức lockForUpdate. Khóa "để cập nhật - for update" ngăn không cho sửa đổi các bản ghi đã chọn hoặc không được chọn bằng một khóa chia sẻ khác:

DB::table('users')
        ->where('votes', '>', 100)
        ->lockForUpdate()
        ->get();

Gỡ lỗi

Bạn có thể sử dụng các phương thức dd và dump khi xây dựng một truy vấn để kết xuất các ràng buộc truy vấn hiện tại và SQL. Phương thức dd sẽ hiển thị các thông tin gỡ lỗi và sau đó dừng thực hiện các yêu cầu. Phương thức dump sẽ hiển thị các thông tin gỡ lỗi nhưng cho phép các yêu cầu tiếp tục thực hiện:

DB::table('users')->where('votes', '>', 100)->dd();

DB::table('users')->where('votes', '>', 100)->dump();
» Tiếp: Pagination (Phân trang)
« Trước: Redis
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!