In this guide, we will go through functionalities provided by SimpleAR's query builder.
The major part of this guide will explain how to use query builder to construct
SELECT
queries, since it is the most used query type.
We'll see how to construct other statements at the end.
You can get a new query builder instance for a model using the query()
method.
$qb = Article::query();
$qb->one(); // Or first(), last(), all().
Query builder provides a good collection of method to add conditions on data to retrieve:
Article::query()->where('author_id', 12);
Fortunately, you don't have to use query() method every time you want to build a query:
Article::where('author_id', 12);
Article::where('author_id', '=', 12); // Same as above
MyModel::whereNot('attr', 'val'); // NOT `attr` = 'val'
MyModel::andWhere('attr', 'val'); // AND `attr` = 'val'
MyModel::orWhere('attr', 'val'); // OR `attr` = 'val'
MyModel::andWhereNot('attr', 'val'); // AND NOT `attr` = 'val'
MyModel::orWhereNot('attr', 'val'); // OR NOT `attr` = 'val'
$query->whereNull('author_id');
// <=>
$query->where('author_id', null);
WHERE `author_id` IS NULL
$query->whereNotNull('author_id');
// <=>
$query->whereNot('author_id', null)
// <=>
$query->where('author_id', '!=', null);
WHERE `author_id` IS NOT NULL
// (You can use where() method too.)
$query->whereTuple(['author_id', 'blog_id'], [[1,2], [1,3], [2,3]]);
WHERE (`author_id`, `blog_id`) IN ((1,2), (1,3), (2,3))
Alternative syntax:
$query->where('author_id,blog_id', [[1,2], [1,3], [2,3]])
Will produce the same as shown above.
Article::whereAttr('comment_count', '>', 'view_count');
WHERE `comment_count` > `view_count`
Use the whereNested
method:
Article::whereNested(function ($q) {
$q->where('author_id', [12, 13, 14])
->andWhere('blog_id', 1);
})
->orWhere(function ($q) {
$q->where('title', 'Alice in Wonderland')
->where('blog_id', 3);
});
WHERE (
`author_id` IN [12, 13, 14] AND `blog_id` = 1
) OR (
`title` = 'Alice in Wonderland' AND `blog_id` = 3
)
whereNested()
is the method that handles nested conditions; but
where()
will get it as well (by delegating to
whereNested()
).
Use whatever method you prefer!
This is really easy and intuitive to perform conditions over linked models in SimpleAR. This section demonstrates it.
Here is the schema I will use in my examples:
Here is the corresponding classes and their relations:
class Blog extends SimpleAR\Model
{
protected static $_relations = array(
'articles' => array(
'type' => 'has_many',
'model' => 'Article',
)
);
}
...
class Article extends SimpleAR\Model
{
public static $_relations = array(
'author' => array(
'type' => 'belongs_to',
'model' => 'Author',
),
'blog' => array(
'type' => 'belongs_to',
'model' => 'Blog',
),
'readers' => array(
'type' => 'many_many',
'model' => 'User'
),
);
}
...
class Author extends SimpleAR\Model {}
...
class User extends SimpleAR\Model {}
Now we have everything we need, let's explore what query builder can offer!
Every attribute condition method (seen above) handles attribute of linked models.
This means that the following is valid:
// Blogs where John Doe has written articles.
Blog::where('articles/author/first_name,last_name', ['John', 'Doe']);
// Blogs where no article has been viewed more than 100 times.
Blog::whereNot('articles/view_count', '>', 100);
This syntax is valid with every method seen in Simple conditions section.
The character "/" is the default relation separator character. You can change
it with queryOptionRelationSeparator
configuration option.
Blog::whereHas('articles');
// With negation
Blog::whereHasNot('articles');
Article::whereHas('readers', '>', 1000);
Blog::whereHas('articles', function ($q) {
$q->where('author_id', 12);
});
Blog::whereHas('articles/readers');
// is equivalent to:
Blog::whereHas('articles', function($q) {
$q->whereHas('readers');
});
// Blogs of which articles readers' average age is greater than 30.
Blog::where(DB::avg('articles/readers/age'), '>', 30);
Smooth!
There are some built-in methods like DB::avg()
: sum()
, count()
... But if
the one you want doesn't exist, you can use fn()
and give it the SQL
function you want to use as first parameter:
// Blogs created before 2010.
Blog:where(DB::fn('YEAR', 'created_at'), '<', 2010);
If none of the available methods is sufficient to build your query, you can use
the whereRaw()
method:
Author::whereRaw(DB::expr("first_name LIKE 'Joe'"));
If you have to use relations in your query, note that:
join()
method;_
(underscore) character.Article::join('author')->whereRaw(DB::expr("author.first_name LIKE 'Joe' AND `_`.`views` > 100"));
Article::where('author_id', 12)
->orderBy('title')
->limit(10)
->offset(20) // Or: limit(10, 20)
->all();
You can use one()
, first()
, last()
instead of all()
if you want just one row.
By default, Query builder return all columns of your table. So if you want just some field, do it like this
Article::where('blogId', 12)
->all(array('author_id', 'title')); // Or one(), first(), last()
SELECT id, author_id, title FROM `articles`;
The primary key of root table are always selected
Article::where('views', '>', 1000)->count();
// 12
Article::where('views', '>', 1000)->count(DB::distinct('id'));
Article::where('views', '>', 1000)->groupBy('authorId')->count('*', 'articleNb');
// array(
// array(
// 'authorId' => 1,
// 'articleNb' => 5,
// ),
// array(
// 'authorId' => 2,
// 'articleNb' => 3,
// ),
// ...
// );
There are several built-in aggregate methods (min
, max
, sum
, avg
,
count
); but if it not sufficient, you can use the generic aggregate
method:
Article::where('blogId', 12)->aggregate('AVG', 'views', 'avg_views');
SELECT AVG(`views`) AS `avg_views` FROM `articles`;
If you want to add an aggregate to the selection but don't want to fetch only
that, use addAggregate()
method. Its signature is the same as aggregate()
but instead of executing the query, it add the aggregate to the list of columns
to select.
User::insert()->fields(['first_name', 'last_name'])->values(
['John', 'Doe'],
['Karl', 'Marx']
)->run();
User::update()->set('first_name', 'Foo')->where('last_name', 'Bar')->run();
Author::delete()->whereHasNot('articles')->run();
$query->groupBy('authorId');
// OR
$query->groupBy(array('authorId', 'first_name'));
GROUP BY `author_id`
/* multiple group by */
GROUP BY `author_id`, `first_name`
The default sort direction is ASC
$query->orderBy('author_id');
// Multiple order by
$query->orderBy(array('author_id', 'first_name'));
ORDER BY `author_id` ASC
/* Multiple order by */
ORDER BY `author_id` ASC, `first_name` ASC
You change the sort direction like this:
$query->orderBy(array('author_id' => 'DESC'));
// Multiple order by
$query->orderBy(array('author_id', 'first_name' => 'DESC'));
ORDER BY `author_id` DESC
/* Multiple order by */
ORDER BY `author_id` ASC, `first_name` DESC
You can use some function like RAND
$query->orderBy(DB::fn('RAND'));
// OR
$query->orderBy(array(DB::fn('YEAR', 'created_at') => 'DESC'));
ORDER BY RAND()
/* OR */
ORDER BY YEAR('created_at') DESC