CI4 Playground v4.7.3
한국어문서
INNER JOIN / LEFT JOIN 실행 결과
쿼리 실행 버튼을 눌러 결과를 확인하세요.
INNER JOIN — Query Builder
$db = \Config\Database::connect();

// INNER JOIN: 양쪽 테이블에 모두 존재하는 행만 반환
$result = $db->table('posts p')
    ->select('p.id, p.title, p.view_count, a.name AS author')
    ->join('accounts a', 'p.author_id = a.id', 'inner')
    ->orderBy('p.id')
    ->get()->getResultArray();
LEFT JOIN — Query Builder
// LEFT JOIN: 왼쪽 테이블 전체 + 오른쪽 일치 행
// 오른쪽에 없으면 NULL 반환
$result = $db->table('users_demo u')
    ->select('u.id, u.username, u.role, k.api_key')
    ->join('api_keys k', 'u.id = k.id', 'left')
    ->orderBy('u.id')
    ->get()->getResultArray();

// join() 세 번째 파라미터
// 'inner' / 'left' / 'right' / 'outer'
// 'left outer' / 'right outer' / 'cross'
서브쿼리 — 평균 조회수 이상인 게시글
쿼리 실행 버튼을 눌러 결과를 확인하세요.
서브쿼리 코드 예제
방법 1: 직접 SQL 서브쿼리
$result = $db->query("
    SELECT id, title, view_count
    FROM posts
    WHERE view_count >= (
        SELECT AVG(view_count) FROM posts
    )
    ORDER BY view_count DESC
")->getResultArray();
방법 2: Query Builder subquery() (CI4 4.3+)
// 서브쿼리 빌더 생성
$subQuery = $db->table('posts')
    ->selectAvg('view_count', 'avg_views');

// 메인 쿼리에서 서브쿼리 사용
$result = $db->table('posts')
    ->where('view_count >=', $subQuery->getCompiledSelect(), false)
    ->orderBy('view_count', 'DESC')
    ->get()->getResultArray();
방법 3: WHERE IN 서브쿼리
// WHERE IN (서브쿼리)
$activeIds = $db->table('api_keys')
    ->select('id')
    ->where('is_active', 1)
    ->getCompiledSelect();

$result = $db->table('users_demo')
    ->whereIn('id', $activeIds, false)
    ->get()->getResultArray();
GROUP BY / HAVING / 집계 함수 결과
쿼리 실행 버튼을 눌러 결과를 확인하세요.
집계 코드 예제
// COUNT, SUM, AVG, MAX, MIN + GROUP BY + HAVING
$result = $db->table('posts')
    ->select('DATE(created_at) AS post_date')
    ->selectCount('*', 'post_count')
    ->selectAvg('view_count', 'avg_views')
    ->selectSum('view_count', 'total_views')
    ->selectMax('view_count', 'max_views')
    ->selectMin('view_count', 'min_views')
    ->groupBy('DATE(created_at)')
    ->having('post_count >=', 1)
    ->orderBy('post_date', 'DESC')
    ->get()->getResultArray();

// 역할별 유저 수
$byRole = $db->table('users_demo')
    ->select('role')
    ->selectCount('*', 'cnt')
    ->groupBy('role')
    ->having('cnt >=', 1)
    ->get()->getResultArray();
Raw SQL 실행 결과
쿼리 실행 버튼을 눌러 결과를 확인하세요.
Raw SQL / query() 코드 예제
파라미터 바인딩 쿼리
$db = \Config\Database::connect();

// ? 플레이스홀더 사용 (SQL 인젝션 방지)
$result = $db->query(
    "SELECT id, title, view_count FROM posts
     WHERE view_count > ? ORDER BY view_count DESC LIMIT 5",
    [100]
)->getResultArray();

// 마지막 실행된 쿼리 확인 (디버깅용)
$lastQuery = $db->getLastQuery();
echo $lastQuery; // 완성된 쿼리 문자열 출력
DB 네이티브 함수 사용
// select()에 false를 전달하면 이스케이프 없이 SQL 표현식 사용 가능
$result = $db->table('posts')
    ->select("id, title, LENGTH(title) AS title_len,
              UPPER(title) AS title_upper", false)
    ->orderBy('title_len', 'DESC')
    ->limit(5)
    ->get()->getResultArray();
트랜잭션과 함께 사용
$db->transStart();

$db->query("UPDATE accounts SET balance = balance - ? WHERE id = ?", [1000, 1]);
$db->query("UPDATE accounts SET balance = balance + ? WHERE id = ?", [1000, 2]);

$db->transComplete();

if ($db->transStatus() === false) {
    // 롤백됨
}
주의: $db->query()를 쓸 때 항상 파라미터 바인딩(?)을 사용해 SQL 인젝션을 방지하세요. 사용자 입력을 쿼리 문자열에 직접 삽입하면 안 됩니다.