I have this query
SELECT ANY_VALUE(id) as id, title FROM `major` where university_id=1 group BY `title` order by id asc
I want to convert it into Laravel Query , I have a model majors and the function as follow
public static function retrieveByUniversityIDForWeb($universityId){
return self::select(DB::raw('ANY_VALUE(id) as id, title'))->from('major')->where('university_id', $universityId)->orderBy('id','desc')->simplePaginate(6);
}
but its not returning me the results , query works in phpmyadmin. Any idea what I missed?
You're declaring the method on your model which references its table by default. Also there's no need for using ANY_VALUE in your query. If you need it for some reason then you can change the select below to selectRaw('ANY_VALUE(id) as id, title')
public static function retrieveByUniversityIDForWeb($universityId)
{
return self::select('id', 'title')
->where('university_id', $universityId)
->orderBy('id', 'desc')
->simplePaginate(6);
}
Related
How to order laravel eloquent query using parent model?
I mean I have an eloquent query where I want to order the query by its parent without using join relationship?
I used whereHas and order by on it, but did not work.
Here is a sample of my code:
$query = Post::whereHas('users')->orderBy('users.created_at')->get();
If you want to order Post by a column in user you have to do a join in some way unless you sort after you retrieve the result so either:
$query = Post::select('posts.*')
->join('users', 'users.id', 'posts.user_id')
->orderBy('users.created_at')->get();
Note that whereHas is not needed anymore because the join (which is an inner join by default) will only result in posts that have a user.
Alternatively you can do:
$query = Post::has('users')
->with('users')
->get()
->sortBy(function ($post) { return $post->users->created_at; });
The reason is that eloquent relationships are queried in a separate query from the one that gets the parent model so you can't use relationship columns during that query.
I have no clue why you wanted to order Posts based on their User's created_at field. Perhaps, a different angle to the problem is needed - like accessing the Post from User instead.
That being said, an orderBy() can accept a closure as parameter which will create a subquery then, you can pair it with whereRaw() to somewhat circumvent Eloquent and QueryBuilder limitation*.
Post::orderBy(function($q) {
return $q->from('users')
->whereRaw('`users`.id = `posts`.id')
->select('created_at');
})
->get();
It should generate the following query:
select *
from `posts`
order by (
select `created_at`
from `users`
where `users`.id = `posts`.id
) asc
A join might serve you better, but there are many ways to build queries.
*As far as I know, the subquery can't be made to be aware of the parent query fields
You can simply orderBy in your Post model.
public function users(){
return $this->belongsTo(User::class, "user_id")->orderByDesc('created_at');
}
I hope this helps you.
You can try
Post::query()
->has('users')
->orderBy(
User::select('created_at')
->whereColumn('id', 'posts.user_id')
->orderBy('created_at')
)
->get();
The sql generated would be like
select * from `posts`
where exists (select * from `users` where `posts`.`user_id` = `users`.`id`)
order by (select `created_at` from `users` where `id` = `posts`.`user_id` order by `created_at` asc) asc
But I guess join would be a simpler approach for this use case.
Laravel Docs - Eloquent - Subquery Ordering
How do you add an optional/OR condition to a eloquent relationship?
E.g I want all the users comments OR where the foreign key (user_id) is NULL.
select * from `comments` where (`user_id` is null OR `comments`.`user_id` in (1, 2, 3)) AND `status` = 1
In the User relationship added orWhereNull
public function comments() {
return $this->hasMany(Comments::class)->orWhereNull('user_id');
}
But Laravel it's running:
select * from `comments` where `user_id` is null and `comments`.`user_id` in (1, 2, 3)
Surprised this hasn't been asked before only thing I found similar was this:
https://laracasts.com/discuss/channels/eloquent/eloquent-orwherenull-when-where-has-no-results
I tried this but it needs the model not the query builder.
return $this->where(function ($query){
return $query::hasMany(Comment::class)->orWhereNull('user_id');
});
I'm using eager loading to fetch the comments for a list of users.
$users = User::with('comments')->where('active', 1)->paginate(10);
It doesn't work because the "orWhere" is sent to the underlying query builder immediately but the foreign key constraint is added when the query is run. I couldn't work out a nice way to sort that but this workaround is fine for my use case where I'm only selecting one row at a time with this relation (granted I should probably use replace it with a getter...):
(Excuse any mistakes, changing model names for clarity):
class Customer
{
public function selectedOrCurrentWeek(): HasOne
{
return $this->hasOne(Week::class, 'id', 'selected_week_id')
->withDefault(function (Week $instance, Customer $parent) {
return $instance->newQuery()
->whereRaw('CURRENT_TIMESTAMP between start_date and end_date')
->where('customer_id', $parent->id)
->first();
});
}
Query log when fetching a customer by ID :-
select * from `customers` where
`customers`.`id` = ?
and `customers`.`deleted_at` is null
limit 1;
select * from `weeks` where
CURRENT_TIMESTAMP between start_date and end_date
and `customer_id` = ?
and `weeks`.`deleted_at` is null
limit 1;
but it will run the second query once per row
You can optimize this further to your need, just giving an idea on query
$users = User::with('comments', function($query){
$query->where('user_id', '=', null)->where('status', '1');
})->paginate(10);
I am trying to exclude a few records from a select that has a null column in its relationship.
This is the query I hope to achieve:
SELECT
FROM modelas ma WHERE
ma.id NOT IN (SELECT ma_id from modelbs where modelbs.updated_at is null)
Model A:
public function modelb(){
return $this->hasMany('App\Modelb');
}
Model B
public function modela(){
return $this->belongsTo('App\Modela');
}
Now, I want to query all models A that have a model B where a certain column of model B ISN'T null.
Here's how i tried:
Modela::whereHas('modelbs', function ($query) {
$query->whereNotNull('myColumnOfModelB');
})->get();
This gave me exactly the records I wanted to exclude from my select
Well, I was able to find out where I was mistaken. So here is a query that achieves that raw sql:
Modela::whereDoesntHave('modelbs', function ($query) {
$query->whereNull('someModelBcolumn');
})->get()
Raw SQL
SELECT
FROM modelas ma WHERE
ma.id NOT IN (SELECT ma_id from modelbs where modelbs.updated_at is null)
The "whereDoesntHave()" is equivalent to "SELECT FROM modelas ma WHERE ma.id NOT IN" whereas the "$query->whereNull()" is the actual subquery equivalent to "(SELECT ma_id from modelbs where modelbs.updated_at IS NULL)"
So i was working around with LeftJoin but i can't do it how i want it.
What i have:
Table 1: Blog_Category
Contains: `category_id`, `name`
Table 2: Blog
Contains: `blog_id`, `category_id`, `title` .... etc.
What i build, but isn't working:
public static function ShowAll() {
return self::leftJoin('Blog', 'Blog_Category.category_id', '=', 'Blog.title')
->selectRaw('Blog_Category.*, count(Blog.blog_id) as Counts')
->groupBy('Blog_Category.category_id')
->get();
}
What i want to get is category_id, name, COUNT(count the blog_id which contain the current category_id)
In one word, i want to get the category count next to the name.
Thank you!
EDIT: Actually i just realized, that i don't need Join at all. I need to make this SQL into function:
SELECT blog_category.category_id AS id,
blog_category.name AS name,
(SELECT COUNT(*) FROM blog WHERE blog.category_id = blog_category.category_id) AS count
FROM blog_category;
Use https://laravel.com/docs/5.5/eloquent and make a model for blogs and blog category and then you can do $category = $blog->category
Well I did it with the most easiest way, with raw Select.
I'm posting the code here, for those who had the same problem:
public static function ShowAll() {
return self::selectRaw('blog_category.category_id AS id, blog_category.name AS name, (SELECT COUNT(*) FROM blog WHERE blog.category_id = blog_category.category_id) AS count')->get();
}
I am converting my existing twitter clone toy project into Laravel 4. I have used codeigniter framework before and Eloquent ORM is the first ORM I have ever touched.
So I have confusion about how to do some advance queries,
Following query Is to fetch all the posts which are created by users who are being followed by current_user. This Stored procedure snippet works fine.
BEGIN
SELECT
tbl_users.id as user_id,
tbl_users.display_name,
tbl_users.username,
tbl_posts.id as post_id,
tbl_posts.post_text,
tbl_posts.`timestamp`
FROM tbl_posts , tbl_users
WHERE tbl_posts.user_id IN (
SELECT tbl_followers.destination_user_id FROM tbl_followers
WHERE tbl_followers.source_user_id = xSource_user_id
)
AND tbl_posts.user_id = tbl_users.id
ORDER BY tbl_posts.id DESC
LIMIT xLimit;
END
Table structure is like below :
users : (id)
posts : (id,src_user_id [FK], post_text )
followers : (id , dest_user_id [FK] , src_user_id [FK])
My best Guess is :
Post::where('user_id', 'IN' , Follower::where('from_user_id','=','1'))->toSql();
I have added following relationships to User model
public function posts()
{
return $this->hasMany('Post');
}
public function followers()
{
return $this->hasMany('Follower');
}
you need to use lists() to get results as array
Post::whereIn('user_id', Follower::where('from_user_id','=','1')->lists('id'))->toSql();
You can use IN in this way:
Post::whereIn('user_id', yourArray)->get();
But I suggest you to take a look at eloquent manual here, especially the relationships part