Laravel 데이터베이스: 쿼리 빌더

1 개요[ | ]

Crystal Clear action info.png 작성 중인 문서입니다.
Database: Query Builder
데이터: 쿼리 빌더

https://laravel.com/docs/11.x/queries

2 소개[ | ]

Laravel의 데이터베이스 쿼리 빌더는 데이터베이스 쿼리를 생성하고 실행하기 위한 편리하고 유연한 인터페이스를 제공합니다. 이 빌더는 애플리케이션에서 대부분의 데이터베이스 작업을 수행하는 데 사용할 수 있으며, Laravel이 지원하는 모든 데이터베이스 시스템과 완벽하게 호환됩니다.

Laravel 쿼리 빌더는 SQL 인젝션 공격으로부터 애플리케이션을 보호하기 위해 PDO 파라미터 바인딩을 사용합니다. 쿼리 빌더에 전달되는 문자열을 클리닝(clean)하거나 정화(sanitize)할 필요가 없습니다.

PDO는 컬럼 이름 바인딩을 지원하지 않습니다. 따라서 사용자 입력이 쿼리에서 참조되는 컬럼 이름, 특히 "order by" 컬럼을 결정하도록 허용해서는 안 됩니다.

3 데이터베이스 쿼리 실행[ | ]

테이블에서 모든 행 조회

다음은 DB 파사드에서 제공하는 table 메소드를 사용하여 쿼리를 시작하는 방법에 대한 설명입니다. table 메소드는 주어진 테이블에 대한 유창한 쿼리 빌더 인스턴스를 반환하며, 이를 통해 쿼리에 더 많은 제약조건을 연쇄적으로 추가하고, 마지막으로 get 메소드를 사용하여 쿼리 결과를 검색할 수 있습니다:

<?php
 
namespace App\Http\Controllers;
 
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
 
class UserController extends Controller
{
    /**
     * Show a list of all of the application's users.
     */
    public function index(): View
    {
        $users = DB::table('users')->get();
 
        return view('user.index', ['users' => $users]);
    }
}

get 메소드는 쿼리 결과를 포함하는 Illuminate\Support\Collection 인스턴스를 반환하며, 각 결과는 PHP의 stdClass 객체의 인스턴스입니다. 각 컬럼의 값은 객체의 속성으로 접근하여 가져올 수 있습니다.

use Illuminate\Support\Facades\DB;
 
$users = DB::table('users')->get();
 
foreach ($users as $user) {
    echo $user->name;
}

Laravel 컬렉션은 데이터를 매핑하고 축소하는 데 매우 강력한 다양한 메소드를 제공합니다. Laravel 콜렉션에 대한 자세한 내용은 콜렉션 문서를 참조하십시오.

테이블에서 단일 행 / 컬럼 조회

데이터베이스 테이블에서 단일 행만 검색해야 하는 경우, DB 파사드의 first 메소드를 사용할 수 있습니다. 이 메소드는 단일 stdClass 객체를 반환합니다:

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

전체 행이 필요하지 않다면, value 메소드를 사용하여 레코드에서 단일 값을 추출할 수 있습니다. 이 메소드는 해당 컬럼의 값을 직접 반환합니다:

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

id 컬럼 값을 기준으로 단일 행을 검색하려면, find 메소드를 사용하세요:

$user = DB::table('users')->find(3);
컬럼 값 목록 조회

단일 컬럼의 값을 포함하는 Illuminate\Support\Collection 인스턴스를 검색하려면 pluck 메소드를 사용할 수 있습니다. 이 예제에서는 사용자 타이틀의 콜렉션을 검색합니다:

use Illuminate\Support\Facades\DB;
 
$titles = DB::table('users')->pluck('title');
 
foreach ($titles as $title) {
    echo $title;
}

결과 콜렉션이 사용할 키를 지정하려면 pluck 메소드의 두 번째 인수로 지정할 수 있습니다:

$titles = DB::table('users')->pluck('title', 'name');
 
foreach ($titles as $name => $title) {
    echo $title;
}

3.1 결과 청킹[ | ]

수천 개의 데이터베이스 레코드를 작업해야 하는 경우, DB 파사드에서 제공하는 chunck 메소드를 사용하는 것을 고려하십시오. 이 메소드는 한 번에 작은 청크의 결과를 가져와 각 청크를 처리할 클로저로 전달합니다. 예를 들어, 한 번에 100개의 레코드를 청크로 나누어 전체 사용자 테이블을 가져오는 방법은 다음과 같습니다:

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
 
DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
    foreach ($users as $user) {
        // ...
    }
});

클로저에서 false를 반환하여 추가 청크 처리를 중단할 수 있습니다:

DB::table('users')->orderBy('id')->chunk(100, function (Collection $users) {
    // 레코드 처리...
 
    return false;
});

결과를 청크로 나누는 동안 데이터베이스 레코드를 업데이트하는 경우, 청크 결과가 예기치 않게 변경될 수 있습니다. 청크로 나눈 후 검색된 레코드를 업데이트할 계획이라면, 항상 chunkById 메소드를 사용하는 것이 좋습니다. 이 메소드는 레코드의 기본키를 기준으로 자동으로 결과를 페이지로 나눕니다:

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

청크 콜백 내부에서 레코드를 업데이트하거나 삭제할 때, 기본키나 외래키에 대한 변경사항이 청크 쿼리에 영향을 줄 수 있습니다. 이로 인해 레코드가 청크 결과에 포함되지 않을 수 있습니다.

3.2 게으른(lazy) 결과 스트리밍[ | ]

lazy 메소드는 chunk 메소드와 유사하게 쿼리를 청크 단위로 실행합니다. 그러나 각 청크를 콜백으로 전달하는 대신, lazy() 메소드는 LazyCollection을 반환하여 결과를 단일 스트림으로 처리할 수 있게 합니다:

use Illuminate\Support\Facades\DB;
 
DB::table('users')->orderBy('id')->lazy()->each(function (object $user) {
    // ...
});

마찬가지로, 검색된 레코드를 반복하면서 업데이트하려는 경우 lazyById 또는 lazyByIdDesc 메소드를 사용하는 것이 좋습니다. 이 메소드들은 레코드의 기본키를 기준으로 결과를 자동으로 페이지화합니다:

DB::table('users')->where('active', false)
    ->lazyById()->each(function (object $user) {
        DB::table('users')
            ->where('id', $user->id)
            ->update(['active' => true]);
    });

레코드를 반복하면서 업데이트하거나 삭제할 때, 기본 키 또는 외래 키에 대한 변경은 청크 쿼리에 영향을 미칠 수 있습니다. 이로 인해 레코드가 결과에 포함되지 않을 수 있습니다.

3.3 집계[ | ]

쿼리 빌더는 count, max, min, avg, sum과 같은 집계 값을 조회하기 위한 다양한 메소드를 제공합니다. 쿼리를 작성한 후 이러한 메소드 중 하나를 호출할 수 있습니다:

use Illuminate\Support\Facades\DB;
 
$users = DB::table('users')->count();
 
$price = DB::table('orders')->max('price');

물론, 이러한 메소드를 다른 절과 결합하여 집계 값을 세밀하게 조정할 수 있습니다:

$price = DB::table('orders')
                ->where('finalized', 1)
                ->avg('price');
레코드 존재 여부 확인

쿼리의 제약 조건에 맞는 레코드가 존재하는지 확인하기 위해 count 메소드를 사용하는 대신, existsdoesntExist 메소드를 사용할 수 있습니다:

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

4 Select 문[ | ]

Select 절 지정하기

데이터베이스 테이블에서 모든 컬럼을 선택하고 싶지 않을 때가 있습니다. select 메소드를 사용하여 쿼리에 대한 커스텀 "select" 절을 지정할 수 있습니다:

use Illuminate\Support\Facades\DB;
 
$users = DB::table('users')
            ->select('name', 'email as user_email')
            ->get();

distinct 메소드를 사용하면 쿼리가 고유한 결과를 반환하도록 강제할 수 있습니다:

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

이미 쿼리 빌더 인스턴스를 가지고 있고 기존 select 절에 열을 추가하려면 addSelect 메소드를 사용할 수 있습니다:

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

5 원시 표현[ | ]

때로는 쿼리에 임의의 문자열을 삽입해야 할 때가 있습니다. 원시 문자열 표현을 만들기 위해서는 DB 파사드에서 제공하는 raw 메소드를 사용할 수 있습니다.

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

원시 문은 문자열로 쿼리에 삽입되므로 SQL 인젝션 취약성을 피하기 위해 매우 신중해야 합니다.

원시 메소드

DB::raw 메소드 대신에 다양한 쿼리의 부분에 원시 표현식을 삽입하기 위해 다음 메소드들을 사용할 수 있습니다. 원시 표현식을 사용하는 쿼리는 SQL 인젝션 취약성으로부터 보호되지 않을 수 있음을 유의하십시오.

selectRaw

selectRaw 메소드는 addSelect(DB::raw(/* ... */)) 대신 사용할 수 있습니다. 이 메소드는 선택적으로 두 번째 인수로 바인딩 배열을 받습니다:

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

whereRaworWhereRaw 메소드는 쿼리에 원시 "where" 절을 삽입하는 데 사용됩니다. 이 메소드는 선택적으로 두 번째 인수로 바인딩 배열을 받습니다:

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

havingRaworHavingRaw 메소드는 "having" 절의 값으로 원시 문자열을 제공하는 데 사용됩니다. 이 메소드는 선택적으로 두 번째 인수로 바인딩 배열을 받습니다:

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

orderByRaw 메소드는 "order by" 절의 값으로 원시 문자열을 제공하는 데 사용됩니다:

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

groupByRaw 메소드는 "group by" 절의 값으로 원시 문자열을 제공하는 데 사용됩니다:

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

6 조인[ | ]

내부 조인(inner join) 절

쿼리 빌더를 사용하여 쿼리에 조인 절을 추가할 수 있습니다. 기본적인 "내부 조인"을 수행하려면 쿼리 빌더 인스턴스의 join 메소드를 사용할 수 있습니다. join 메소드에 전달되는 첫 번째 인수는 조인할 테이블의 이름이며, 나머지 인수는 조인에 필요한 컬럼 제약조건을 지정합니다. 단일 쿼리에서 여러 테이블을 조인할 수도 있습니다:

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();
왼쪽 조인(left join) / 오른쪽 조인(right join) 절

"내부 조인" 대신 "왼쪽 조인" 또는 "오른쪽 조인"을 수행하려면 leftJoin 또는 rightJoin 메소드를 사용하세요. 이 메소드의 시그니처는 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();
교차 조인(cross join) 절

crossJoin 메소드를 사용하여 "교차 조인"을 수행할 수 있습니다. 교차 조인은 첫 번째 테이블과 조인된 테이블 간의 카티전 곱을 생성합니다:

$sizes = DB::table('sizes')
            ->crossJoin('colors')
            ->get();
고급 조인 절

더 고급 조인 절을 지정할 수도 있습니다. 시작하려면, join 메소드의 두 번째 인수로 클로저를 전달하세요. 클로저는 Illuminate\Database\Query\JoinClause 인스턴스를 수신하여 "조인" 절에 대한 제약조건을 지정할 수 있습니다:

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

조인에 "where" 절을 사용하려면 JoinClause 인스턴스에서 제공하는 whereorWhere 메소드를 사용할 수 있습니다. 이 메소드들은 두 컬럼을 비교하는 대신 컬럼을 값과 비교합니다:

DB::table('users')
        ->join('contacts', function (JoinClause $join) {
            $join->on('users.id', '=', 'contacts.user_id')
                 ->where('contacts.user_id', '>', 5);
        })
        ->get();
서브쿼리 조인

joinSub, leftJoinSub, rightJoinSub 메소드를 사용하여 쿼리를 서브쿼리에 조인할 수 있습니다. 이 메소드 각각은 서브쿼리, 테이블 별칭, 관련 컬럼을 정의하는 클로저를 세 인수로 받습니다. 이 예제에서는 각 사용자 레코드에 사용자의 가장 최근에 게시된 블로그 게시물의 created_at 타임스탬프도 포함된 사용자 콜렉션을 검색합니다:

$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 (JoinClause $join) {
            $join->on('users.id', '=', 'latest_posts.user_id');
        })->get();
래터럴 조인(lateral join)

Warning

래터럴 조인은 현재 PostgreSQL, MySQL >= 8.0.14, SQL Server에서 지원됩니다.

joinLateral, leftJoinLateral 메소드를 사용하여 서브쿼리와 "래터럴 조인"을 수행할 수 있습니다. 이 메소드 각각은 두 인수, 서브쿼리와 테이블 별칭을 받습니다. 조인 조건은 주어진 서브쿼리의 where 절 내에 지정해야 합니다. 래터럴 조인은 각 행에 대해 평가되며 서브쿼리 외부의 컬럼을 참조할 수 있습니다.

이 예제에서는 각 사용자와 사용자의 가장 최근의 블로그 게시물 세 개를 조회합니다. 각 사용자는 결과 집합에서 최대 세 개의 행을 생성할 수 있으며, 각 행은 사용자의 가장 최근 블로그 게시물에 해당합니다. 조인 조건은 현재 사용자 행을 참조하는 서브쿼리 내의 whereColumn 절로 지정됩니다:

$latestPosts = DB::table('posts')
                   ->select('id as post_id', 'title as post_title', 'created_at as post_created_at')
                   ->whereColumn('user_id', 'users.id')
                   ->orderBy('created_at', 'desc')
                   ->limit(3);

$users = DB::table('users')
            ->joinLateral($latestPosts, 'latest_posts')
            ->get();

7 유니온[ | ]

8 기본 Where 절[ | ]

8.1 Where 절[ | ]

쿼리 빌더의 where 메소드를 사용하여 쿼리에 "where" 절을 추가할 수 있습니다. where 메소드의 가장 기본적인 호출에는 세 개의 인수가 필요합니다. 첫 번째 인수는 컬럼의 이름입니다. 두 번째 인수는 데이터베이스에서 지원하는 연산자 중 하나입니다. 세 번째 인수는 컬럼의 값과 비교할 값입니다.

예를 들어, 다음 쿼리는 votes 컬럼의 값이 100이고 age 컬럼의 값이 35보다 큰 사용자를 조회합니다:

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

편의를 위해, 컬럼이 주어진 값과 같음(=)을 확인하려는 경우, 두 번째 인수로 값을 전달할 수 있습니다. Laravel은 = 연산자를 사용하려 한다고 가정합니다:

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

앞서 언급했듯이, 데이터베이스 시스템에서 지원하는 모든 연산자를 사용할 수 있습니다:

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

또한 조건의 배열을 where 함수에 전달할 수도 있습니다. 배열의 각 요소는 일반적으로 where 메소드에 전달되는 세 개의 인수를 포함하는 배열이어야 합니다:

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

PDO는 컬럼 이름 바인딩을 지원하지 않습니다. 따라서 쿼리에서 참조되는 컬럼 이름을 사용자 입력에 의해 결정되도록 해서는 안 됩니다. 여기에는 "order by" 컬럼이 포함됩니다.

8.2 Or Where 절[ | ]

Query Builder의 where 메소드를 연속으로 호출할 때, "where" 절들은 and 연산자로 결합됩니다. 그러나 orWhere 메소드를 사용하여 or 연산자로 절을 쿼리에 추가할 수 있습니다. orWhere 메소드는 where 메소드와 동일한 인수를 받습니다:

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

괄호 안에 "or" 조건을 그룹화해야 하는 경우, orWhere 메소드의 첫 번째 인수로 클로저를 전달할 수 있습니다:

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

위의 예제는 다음 SQL을 생성합니다:

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

전역 스코프가 적용될 때 예기치 않은 동작을 방지하기 위해 항상 orWhere 호출을 그룹화해야 합니다.

8.3 Where Not 절[ | ]

whereNotorWhereNot 메소드는 주어진 그룹의 쿼리 제약 조건을 부정하는 데 사용할 수 있습니다. 예를 들어, 다음 쿼리는 클리어런스 중이거나 가격이 10보다 적은 제품을 제외합니다:

$products = DB::table('products')
                ->whereNot(function (Builder $query) {
                    $query->where('clearance', true)
                          ->orWhere('price', '<', 10);
                })
                ->get();

8.4 Where Any / All 절[ | ]

때로는 여러 컬럼에 동일한 쿼리 제약조건을 적용해야 할 때가 있습니다. 예를 들어, 주어진 목록의 모든 컬럼이 특정 값과 LIKE 조건에 맞는 모든 레코드를 조회하고 싶을 수 있습니다. 이를 위해 whereAny 메소드를 사용할 수 있습니다:

$users = DB::table('users')
            ->where('active', true)
            ->whereAny([
                'name',
                'email',
                'phone',
            ], 'LIKE', 'Example%')
            ->get();

위의 쿼리는 다음 SQL로 변환됩니다:

SELECT *
FROM users
WHERE active = true AND (
    name LIKE 'Example%' OR
    email LIKE 'Example%' OR
    phone LIKE 'Example%'
)

마찬가지로, whereAll 메소드를 사용하여 주어진 모든 컬럼이 특정 제약조건에 맞는 레코드를 조회할 수 있습니다:

$posts = DB::table('posts')
            ->where('published', true)
            ->whereAll([
                'title',
                'content',
            ], 'LIKE', '%Laravel%')
            ->get();

위의 쿼리는 다음 SQL로 변환됩니다:

SELECT *
FROM posts
WHERE published = true AND (
    title LIKE '%Laravel%' AND
    content LIKE '%Laravel%'
)

8.5 JSON Where 절[ | ]

Laravel은 JSON 컬럼 유형을 지원하는 데이터베이스에서 JSON 컬럼 유형을 쿼리하는 것을 지원합니다. 현재 MySQL 8.0+, PostgreSQL 12.0+, SQL Server 2017+, SQLite 3.39.0+ (JSON1 확장 포함)이 이에 해당합니다. JSON 컬럼을 쿼리하려면 -> 연산자를 사용하세요:

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

JSON 배열을 쿼리하려면 whereJsonContains를 사용할 수 있습니다:

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

MySQL 또는 PostgreSQL 데이터베이스를 사용하는 경우, whereJsonContains 메소드에 값을 배열로 전달할 수 있습니다:

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

JSON 배열의 길이를 기준으로 쿼리하려면 whereJsonLength 메소드를 사용할 수 있습니다:

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

8.6 추가 Where 절[ | ]

whereBetween / orWhereBetween

whereBetween 메소드는 컬럼의 값이 두 값 사이에 있는지 확인합니다:

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

whereNotBetween 메소드는 컬럼의 값이 두 값 사이에 있지 않은지 확인합니다:

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

whereBetweenColumns 메소드는 같은 테이블 행에 있는 두 컬럼 값 사이에 있는지 확인합니다:

$patients = DB::table('patients')
                       ->whereBetweenColumns('weight', ['minimum_allowed_weight', 'maximum_allowed_weight'])
                       ->get();

whereNotBetweenColumns 메소드는 같은 테이블 행에 있는 두 컬럼 값 사이에 있지 않은지 확인합니다:

$patients = DB::table('patients')
                       ->whereNotBetweenColumns('weight', ['minimum_allowed_weight', 'maximum_allowed_weight'])
                       ->get();
whereIn / whereNotIn / orWhereIn / orWhereNotIn

whereIn 메소드는 주어진 컬럼의 값이 주어진 배열 내에 있는지 확인합니다:

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

whereNotIn 메소드는 주어진 컬럼의 값이 주어진 배열 내에 없는지 확인합니다:

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

whereIn 메소드의 두 번째 인자로 쿼리 객체를 제공할 수도 있습니다:

$activeUsers = DB::table('users')->select('id')->where('is_active', 1);
 
$users = DB::table('comments')
                    ->whereIn('user_id', $activeUsers)
                    ->get();

위의 예는 다음 SQL을 생성합니다:

select * from comments where user_id in (
    select id
    from users
    where is_active = 1
)

Warning

대량의 정수 바인딩을 쿼리에 추가하는 경우, whereIntegerInRaw 또는 whereIntegerNotInRaw 메소드를 사용하여 메모리 사용량을 크게 줄일 수 있습니다.

whereNull / whereNotNull / orWhereNull / orWhereNotNull

whereNull 메소드는 주어진 컬럼의 값이 NULL인지 확인합니다:

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

whereNotNull 메소드는 주어진 컬럼의 값이 NULL이 아닌지 확인합니다:

$users = DB::table('users')
                ->whereNotNull('updated_at')
                ->get();
whereDate / whereMonth / whereDay / whereYear / whereTime

whereDate 메소드는 컬럼의 값을 특정 날짜와 비교하는 데 사용됩니다:

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

whereMonth 메소드는 컬럼의 값을 특정 월과 비교하는 데 사용됩니다:

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

whereDay 메소드는 컬럼의 값을 특정 일과 비교하는 데 사용됩니다:

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

whereYear 메소드는 컬럼의 값을 특정 연도와 비교하는 데 사용됩니다:

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

whereTime 메소드는 컬럼의 값을 특정 시간과 비교하는 데 사용됩니다:

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

whereColumn 메소드는 두 컬럼이 같은지 확인하는 데 사용됩니다:

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

whereColumn 메소드에 비교 연산자를 전달할 수도 있습니다:

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

또한 whereColumn 메소드에 컬럼 비교 배열을 전달할 수도 있습니다. 이러한 조건은 and 연산자로 연결됩니다:

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

8.7 논리적 그룹화[ | ]

쿼리의 원하는 논리적 그룹화를 달성하기 위해 여러 "where" 절을 괄호 안에 그룹화해야 할 때가 있습니다. 사실, 예상치 못한 쿼리 동작을 피하기 위해 orWhere 메소드 호출을 항상 괄호 안에 그룹화하는 것이 좋습니다. 이를 달성하기 위해, 클로저를 where 메소드에 전달할 수 있습니다:

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

보시다시피, 클로저를 where 메소드에 전달하면 쿼리 빌더가 제약조건 그룹을 시작하도록 지시합니다. 클로저는 쿼리 빌더 인스턴스를 받게 되며, 이 인스턴스를 사용하여 괄호 그룹에 포함되어야 하는 제약 조건을 설정할 수 있습니다. 위의 예제는 다음과 같은 SQL을 생성합니다:

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

Warning

글로벌 스코프가 적용될 때 예상치 못한 동작을 피하기 위해 항상 orWhere 호출을 그룹화해야 합니다.

9 고급 Where 절[ | ]

9.1 Where Exists 절[ | ]

whereExists 메소드는 "where exists" SQL 절을 작성할 수 있게 해줍니다. whereExists 메소드는 클로저를 인수로 받습니다. 이 클로저는 쿼리 빌더 인스턴스를 받게 되며, "exists" 절 내에 배치될 쿼리를 정의할 수 있게 합니다:

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

또는, 클로저 대신 쿼리 객체를 whereExists 메소드에 제공할 수도 있습니다:

$orders = DB::table('orders')
                ->select(DB::raw(1))
                ->whereColumn('orders.user_id', 'users.id');

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

위의 두 예제는 모두 다음 SQL을 생성합니다:

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

9.2 서브쿼리 Where 절[ | ]

때로는 주어진 값과 서브쿼리의 결과를 비교하는 "where" 절을 구성해야 할 때가 있습니다. 이를 위해 클로저와 값을 where 메소드에 전달할 수 있습니다. 예를 들어, 다음 쿼리는 주어진 유형의 최근 "membership(회원권)"을 가진 모든 사용자를 조회합니다;

use App\Models\User;
use Illuminate\Database\Query\Builder;
 
$users = User::where(function (Builder $query) {
    $query->select('type')
        ->from('membership')
        ->whereColumn('membership.user_id', 'users.id')
        ->orderByDesc('membership.start_date')
        ->limit(1);
}, 'Pro')->get();

또는, 컬럼을 서브쿼리 결과와 비교하는 "where" 절을 구성해야 할 수도 있습니다. 이를 위해 컬럼, 연산자, 클로저를 where 메소드에 전달할 수 있습니다. 예를 들어, 다음 쿼리는 금액이 평균보다 적은 모든 소득 기록을 검색합니다;

use App\Models\Income;
use Illuminate\Database\Query\Builder;
 
$incomes = Income::where('amount', '<', function (Builder $query) {
    $query->selectRaw('avg(i.amount)')->from('incomes as i');
})->get();

9.3 전체 텍스트 Where 절[ | ]

Warning

전체 텍스트 Where 절은 현재 MySQL과 PostgreSQL에서 지원됩니다.

whereFullTextorWhereFullText 메소드는 전체 텍스트 인덱스가 있는 컬럼에 대해 쿼리에 전체 텍스트 "where" 절을 추가하는 데 사용될 수 있습니다. 이러한 메소드는 Laravel에 의해 기본 데이터베이스 시스템에 맞는 적절한 SQL로 변환됩니다. 예를 들어, MySQL을 사용하는 애플리케이션에서는 MATCH AGAINST 절이 생성됩니다:

$users = DB::table('users')
           ->whereFullText('bio', 'web developer')
           ->get();

10 정렬, 그룹화, 리미트, 오프셋[ | ]

10.1 정렬[ | ]

orderBy 메소드

orderBy 메소드는 주어진 컬럼에 따라 쿼리 결과를 정렬할 수 있도록 해줍니다. orderBy 메소드가 받아들이는 첫 번째 인자는 정렬하려는 컬럼이며, 두 번째 인자는 정렬 방향으로 asc(오름차순) 또는 desc(내림차순) 중 하나를 사용할 수 있습니다:

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

여러 컬럼에 따라 정렬하려면 orderBy를 필요한 만큼 여러 번 호출하면 됩니다:

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

latestoldest 메소드는 날짜에 따라 쉽게 결과를 정렬할 수 있도록 해줍니다. 기본적으로 결과는 테이블의 created_at 컬럼에 따라 정렬됩니다. 또는 정렬하려는 컬럼 이름을 전달할 수도 있습니다:

$user = DB::table('users')
                ->latest()
                ->first();
랜덤 정렬

inRandomOrder 메소드는 쿼리 결과를 랜덤으로 정렬할 때 사용할 수 있습니다. 예를 들어, 이 메소드를 사용하여 랜덤 사용자 하나를 가져올 수 있습니다:

$randomUser = DB::table('users')
                ->inRandomOrder()
                ->first();
기존 정렬 제거하기

reorder 메소드는 쿼리에 이전에 적용된 모든 "order by" 절을 제거합니다:

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

reorder 메소드를 호출할 때 컬럼과 방향을 전달하면 모든 기존 "order by" 절을 제거하고 쿼리에 완전히 새로운 정렬을 적용할 수 있습니다:

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

10.2 그룹화[ | ]

10.3 리미트, 오프셋[ | ]

11 조건절[ | ]

12 Insert 문[ | ]

12.1 Upsert[ | ]

13 Update 문[ | ]

13.1 JSON 컬럼 업데이트[ | ]

13.2 증가 및 감소[ | ]

14 Delete 문[ | ]

15 비관적 락[ | ]

16 디버깅[ | ]

문서 댓글 ({{ doc_comments.length }})
{{ comment.name }} {{ comment.created | snstime }}