To add columns to the Select, use the columns()
method and pass each column as
a variadic argument.
// SELECT id, name AS namecol, COUNT(foo) AS foo_count
$select
->columns('id')
->columns('name AS namecol', 'COUNT(foo) AS foo_count');
To add a FROM
clause, use the from()
method:
// FROM foo, bar AS b
$select
->from('foo')
->from('bar AS b');
(All JOIN
methods support inline value binding via optional trailing arguments.)
To add a JOIN
clause, use the join()
method:
// LEFT JOIN doom AS d ON foo.id = d.foo_id
$select->join(
'LEFT',
'doom AS d',
'foo.id = d.foo_id'
);
You can concatenate onto the end of the most-recent JOIN
using the catJoin()
method:
// LEFT JOIN doom AS d ON foo.id = d.foo_if AND d.bar = :__1__ AND d.baz = :__2__
$select
->join(
'LEFT',
'doom AS d',
'foo.id = d.foo_id AND d.bar = ',
$bar_value
)->catJoin(' AND d.baz = ', $baz_value);
(All WHERE
methods support implicit and sprintf() inline value binding.)
To add WHERE
conditions, use the where()
method. Additional calls to
where()
will implicitly AND the subsequent condition.
// WHERE bar > :__1__ AND zim >= :__2__ AND baz :__3__
$select
->where('bar > ', $bar_value)
->where('zim >= ', $zim_value)
->andWhere('baz < ', $baz_value);
Use orWhere()
to OR the subsequent condition.
// WHERE bar > :__1__ OR zim >= :__2__
$select
->where('bar > ', $bar_value)
->orWhere('zim >= ', $zim_value)
You can concatenate onto the end of the most-recent WHERE
condition using the
catWhere()
method:
// WHERE bar > :__1__ OR (foo = 88 AND bar < :__2__)
$select
->where('bar > ', $bar_value)
->orWhere('(')
->catWhere('foo = 88')
->catWhere(' AND bar < ', $bar_value)
->catWhere(')');
Each of the WHERE-related methods has an sprintf
variation as well:
// WHERE bar BETWEEN :__1__ AND :__2__
// AND baz BETWEEN :__3__ AND :__4__
// OR dib BETWEEN :__5__ AND :__6___
// ...
$select
->whereSprintf('bar BETWEEN %s AND %s', $bar_low, $bar_high)
->andWhereSprintf('baz BETWEEN %s AND %s', $baz_low, $baz_high)
->orWhereSprintf('dib BETWEEN %s AND %s', $dib_low, $dib_high)
->catWhereSprintf(...);
There is an additional whereEquals()
convenience method that adds a series of
AND
ed equality conditions for you based on an array of key-value pairs:
IN ()
.FALSE
(which means the query will return no results).null
value, the condition will be IS NULL
.=
.If you pass a key without a value, that key will be used as a raw unescaped condition.
For example:
// WHERE foo IN (:__1__, :__2__, :__3__)
// AND bar IS NULL
// AND baz = :__4__
// AND zim = NOW()
// AND FALSE
$select->whereEquals([
'foo' => ['a', 'b', 'c'],
'bar' => null,
'baz' => 'dib',
'zim = NOW()',
'gir' => [],
]);
To add GROUP BY
expressions, use the groupBy()
method and pass each
expression as a variadic argument.
// GROUP BY foo, bar, baz
$select
->groupBy('foo')
->groupBy('bar', 'baz');
(All HAVING
methods support implicit and sprintf() inline value binding.)
The HAVING
methods work just like their equivalent WHERE methods:
having()
and andHaving()
AND a HAVING conditionorHaving()
ORs a HAVING conditioncatHaving()
concatenates onto the end of the most-recent HAVING conditionhavingSprintf()
and andHavingSprintf()
AND a HAVING condition with sprintf()orHavingSprintf()
ORs a HAVING condition with sprintf()catHavingSprintf()
concatenates onto the end of the most-recent HAVING condition with sprintf()To add ORDER BY
expressions, use the orderBy()
method and pass each
expression as a variadic argument.
// ORDER BY foo, bar, baz
$select
->orderBy('foo')
->orderBy('bar', 'baz');
By default, results are ordered in ascending order (ASC). To sort in a different order, add the revelant keyword. For example, to sort in descending order:
// ORDER BY foo DESC
$select
->orderBy('foo DESC')
To set a LIMIT
and OFFSET
, use the limit()
and offset()
methods.
// LIMIT 10 OFFSET 40
$select
->limit(10)
->offset(40);
Alternatively, you can limit by "pages" using the page()
and perPage()
methods:
// LIMIT 10 OFFSET 40
$select
->page(5)
->perPage(10);
You can set DISTINCT
and FOR UPDATE
flags on the query like so:
$select
->distinct()
->forUpdate();
Each of those methods take an option boolean parameter to enable (true
) or
disable (false
) the flag.
You can set flags recognized by your database server using the setFlag()
method. For example, you can set a MySQL HIGH_PRIORITY
flag like so:
// SELECT HIGH_PRIORITY * FROM foo
$select
->columns('*')
->from('foo')
->setFlag('HIGH_PRIORITY');
To UNION
or UNION ALL
the current Select with a followup query, call one
the union*()
methods:
// SELECT id, name FROM foo
// UNION
// SELECT id, name FROM bar
$select
->columns('id', 'name')
->from('foo')
->union()
->columns('id', 'name')
->from('bar');
// SELECT id, name FROM foo
// UNION ALL
// SELECT id, name FROM bar
$select
->columns('id', 'name')
->from('foo')
->unionAll()
->columns('id', 'name')
->from('bar');
The Select class comes with the following methods to "reset" various clauses
a blank state. This can be useful when reusing the same query in different
variations (e.g., to re-issue a query to get a COUNT(*)
without a LIMIT
, to
find the total number of rows to be paginated over).
reset()
removes all clauses from the query.resetColumns()
removes all the columns to be selected.resetFrom()
removes the FROM clause, including all JOIN sub-clauses.resetWhere()
removes all WHERE conditions.resetGroupBy()
removes all GROUP BY expressions.resetHaving()
removes all HAVING conditions.resetOrderBy()
removes all ORDER BY expressions.resetLimit()
removes all LIMIT, OFFSET, and paging values.resetFlags()
removes all flags.Resetting only works on the current SELECT being built; it has no effect on queries that are already part of UNION.
If you want create a subselect, call the subSelect()
method:
$subSelect = $select->subSelect();
The returned object will be a new Select that shares bound values with the parent Select.
When you are done building the subselect, give it an alias using the as()
method, and call getStatement()
to render it into the desired condition or
expression.
The following is a contrived example:
// SELECT * FROM (
// SELECT id, name
// FROM foo
// WHERE id > :__1__
// ) AS subfoo
// WHERE LENGTH(subfoo.name) > :__2__
$select
->columns('*')
->from(
$select->subSelect()
->columns('id', 'name')
->from('foo')
->where('id > ', $id)
->as('sub_alias')
->getStatement()
)
)
->where('LENGTH(sub_alias.name) > ', $length);
The above shows how the bound values are shared between the parent and the sub Select objects. If you create a new Select and try to use it as a subselect, the bound values will not be shared, and you may get unexpected results.
Other examples include:
// joining on a subselect
$select->join(
'LEFT',
$select->subSelect()->...->as('sub_alias')->getStatement(),
'foo.id = sub_alias.id',
);
// binding a subselect inline; note that it does not need to be
// converted to a string via getStatement()
$select->where(
'foo IN ',
$select->subSelect()->...
);
Once you have built the query, call the perform()
method to execute it and
get back a PDOStatement.
$result = $select->perform();
The Select proxies all fetch*()
and yield()
method calls to the underlying
Connection object via the magic __call()
method, which means you can both
build the query and perform it using the same Select object.
The Connection fetch*()
and yield*()
methods proxied through the Select
are as follows:
fetchAll() : array
fetchAffected() : int
fetchColumn(int $column = 0) : array
fetchGroup(int $style = PDO::FETCH_COLUMN) : array
fetchKeyPair() : array
fetchObject(string $class = 'stdClass', array $args = []) : object
fetchObjects(string $class = 'stdClass', array $args = []) : array
fetchOne() : ?array
fetchUnique() : array
fetchValue() : mixed
yieldAll() : Generator
yieldColumn(int $column = 0) : Generator
yieldKeyPair() : Generator
yieldObjects(string $class = 'stdClass', array $args = []) : Generator
yieldUnique() : Generator
For example, to build a query and get back an array of all results:
// SELECT * FROM foo WHERE bar > :__1__
$result = $select
->columns('*')
->from('foo')
->where('bar > ', $value)
->fetchAll();
foreach ($result as $key => $val) {
echo $val['bar'] . PHP_EOL;
}
For more information on the fetch*()
and yield*()
methods, please see the
Atlas.Pdo Connection
documentation.