Query Builder
A fluent SQL builder for constructing complex queries.
Table of contents
Creating a Query Builder
$qb = $connection->createQueryBuilder();
SELECT
$rows = $connection->createQueryBuilder()
->select('u.id', 'u.email')
->from('users', 'u')
->where('u.is_active = :active')
->orderBy('u.id', 'DESC')
->setOffset(20)
->setLimit(10)
->setParameter('active', 1)
->fetchAllAssociative();
Array-based WHERE
You can pass associative arrays to where(), andWhere(), and orWhere():
$rows = $connection->createQueryBuilder()
->select('*')
->from('users')
->where(['email' => 'alice@example.com', 'is_active' => 1])
->fetchAllAssociative();
// SELECT * FROM users WHERE email = :w_email AND is_active = :w_is_active
Supported operators:
->where(['deleted_at' => null]) // IS NULL
->where(['deleted_at !=' => null]) // IS NOT NULL
->where(['status' => ['active', 'pending']]) // IN
->where(['status !=' => ['banned']]) // NOT IN
->where(['age >=' => 18, 'score <' => 100]) // comparisons
->where(['name LIKE' => 'A%']) // LIKE
->where(['name ILIKE' => 'a%']) // ILIKE (PostgreSQL)
->where(['name NOT LIKE' => '%bot%']) // NOT LIKE
->where(['age BETWEEN' => [18, 65]]) // BETWEEN
Notes:
- Empty
INarray compiles to1 = 0. - Empty
NOT INarray compiles to1 = 1. ILIKEis PostgreSQL-specific.
OR Conditions
Two ways to compose OR groups.
Method-based:
$rows = $connection->createQueryBuilder()
->select('*')
->from('users')
->whereOr(
['status' => 'active', 'age >' => 18],
['role' => 'admin'],
)
->fetchAllAssociative();
Nested keys ($or, $and) inside array:
$rows = $connection->createQueryBuilder()
->select('*')
->from('users')
->where([
'age >' => 18,
'$or' => [
['status' => 'active'],
['$and' => [
['role' => 'admin'],
['verified' => true],
]],
],
])
->fetchAllAssociative();
Available SELECT clauses
| Method | Description |
|---|---|
select(...$columns) |
Set columns to select |
from($table, $alias) |
Set the table and optional alias |
leftJoin($table, $alias, $condition) |
Add a LEFT JOIN |
innerJoin($table, $alias, $condition) |
Add an INNER JOIN |
rightJoin($table, $alias, $condition) |
Add a RIGHT JOIN |
where($expression) |
Set the WHERE clause (replaces previous) |
andWhere($expression) |
Add an AND condition to WHERE |
orWhere($expression) |
Add an OR condition to WHERE |
whereOr(...$groups) |
Replace WHERE with OR-composed groups |
andWhereOr(...$groups) |
Append OR-composed groups with AND |
groupBy(...$columns) |
Set GROUP BY columns |
having($expression) |
Set the HAVING clause |
orderBy($column, $direction) |
Set ORDER BY (replaces previous) |
addOrderBy($column, $direction) |
Add an additional ORDER BY |
setLimit($limit) |
Set the LIMIT |
setOffset($offset) |
Set the OFFSET |
INSERT / UPDATE / DELETE
$connection->createQueryBuilder()
->insert('users')
->values([
'email' => ':email',
'is_active' => ':is_active',
])
->setParameter('email', 'alice@example.com')
->setParameter('is_active', 1)
->executeStatement();
$connection->createQueryBuilder()
->update('users')
->values(['is_active' => ':is_active'])
->where('id = :id')
->setParameter('is_active', 0)
->setParameter('id', 1)
->executeStatement();
$connection->createQueryBuilder()
->delete('users')
->where('id = :id')
->setParameter('id', 1)
->executeStatement();
Parameters
Use named parameters with :paramName syntax:
$qb->where('status = :status')
->setParameter('status', 'active');
Or positional parameters with ?:
$qb->where('status = ?')
->setParameter(0, 'active');
Getting the Raw SQL
$sql = $qb->getSQL();
// e.g. "SELECT u.id, u.email FROM users u WHERE u.is_active = :active"
UPSERT
$sql = $connection->createQueryBuilder()
->upsert('users')
->values(['email' => ':email', 'name' => ':name'])
->onConflict('email')
->doUpdateSet(['name'])
->getSQL();
UPSERT is dialect-aware (mysql, pgsql, sqlite).
Executing Queries
| Method | Description | Use for |
|---|---|---|
fetchAllAssociative() |
Returns all rows as arrays | SELECT |
fetchAssociative() |
Returns a single row | SELECT |
fetchOne() |
Returns a single scalar | SELECT COUNT, etc. |
executeQuery() |
Returns a PDOStatement |
SELECT |
executeStatement() |
Returns affected row count | INSERT/UPDATE/DELETE |