Query Builder 고급
JOIN, 서브쿼리, GROUP BY / HAVING 집계, Raw SQL 직접 실행 등 Query Builder의 고급 기능을 학습합니다.
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 인젝션을 방지하세요.
사용자 입력을 쿼리 문자열에 직접 삽입하면 안 됩니다.