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();
}
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
I am trying to figure out how to get the posts that belong to some filters given by the user. For example, the user gives some filters in this case filter with id 3 and 5. I tried eloquent queries with where Has statement but none of them worked. I am using Lumen, if you guys need the table view please let me know.
The code I am trying to get the posts with:
The problem here is that it gets all the posts that have filter_id 3 or 5:
$post = Post::whereHas('filters', function ($q){
$q->whereIn('filters_id',[3,5]);
})->get();
The problem here is that it gets all the posts that in the assigneds table for filter_id have 3
$post = Post::whereHas('filters', function ($q){
$q->where(['filters_id'=> [3,5]]);
})->get();
Post Model:
class Post extends Model {
public function filters(){
return $this->belongsToMany(Filters::class, 'assigneds','post_id','filters_id');
}
Filters Model:
class Filters extends Model {
public function posts(){
return $this->belongsToMany(Post::class, 'assigneds','post_id','filters_id');
}
I have also tried writing direcly the query like this:
select * from posts where exists (select * from filters inner join assigneds on filters.id=assigneds.filters_id where posts.id= assigneds.post_id and (filters_id=3 and filters_id=5))
But it didn't work. Since I am trying to get the posts that belong to id 3 and 5 where In will not do the job, also filter id 3 and 5 are only for testing, I am trying to find a proper way to get the posts that belong te each element on the array.
Example:
array = [3,7,8,10]
Get all the posts that have assigned filter_id 3 and 7 and 8 and 10
SELECT and
, qualify
, only
, the
, columns
, you
, actually
, want
FROM posts p
JOIN assigneds a
ON a.post_id = p.id
JOIN filters f
ON f.id = a.filters_id
WHERE a.filters_id IN(3,5)
GROUP
BY all
, unaggregated
, columns
, appearing
, in
, the
, select
, clause
HAVING COUNT(*) = 2; -- (or COUNT(DISTINCT something))
Okay, so this one worked fine for me, although it takes more time than I prefer for now I can't do better, if I go back to this project in the future and I make changes I will comment in this reply.
$temp = $request->filter_id;
$post = Post::whereDoesntHave('filters', function ($q) use ($temp){
foreach($temp as $filter){
$q->where('filters_id', '!=' , $filter);
}
})->get();
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);
}
I have 3 tables. Players, player_skills and Skills.
Players
- bb1_player_id
Skills
- bb1_skill_id
Player_skills
- bb1_player_id
- bb1_skill_id
I have created the Player Model with this method.
public function skills()
{
return $this->belongsToMany('App\Skills', 'player_skills', 'bb1_player_id', 'bb1_skill_id');
}
That outputs this Query:
"select `skills`.*, `player_skills`.`bb1_player_id` as `pivot_bb1_player_id`, `player_skills`.`bb1_skill_id` as `pivot_bb1_skill_id` from `skills` inner join `player_skills` on `skills`.`id` = `player_skills`.`bb1_skill_id` where `player_skills`.`bb1_player_id` = ?"
The query works, but I am hoping to get a query that does not every use the id field of the tables and only uses the fields I am specifying. It uses both the id of the skill and player.id at the '?' of the query. Is there a way around this? Or do I need to rework my tables to conform?
I have also tried adding more options like below to no avail.
public function skills()
{
return $this->belongsToMany('App\Skills', 'player_skills','bb1_player_id','bb1_skill_id','bb1_player_id','bb1_skill_id');
}
Basically, I've got this coding convention that any primary key which is an ID, I will call the column name "id". So here comes my problem. I'm joining two tables and I'm getting the ID of the second table instead of the first table. I know if I use select "artists.id, ..." it will work, but I want to know if there's a fix with using "select *" which would be better for future expansion (new colums will come ...).
Here's my model:
$this->db->select('*');
$this->db->from('artists');
$this->db->join('categories', 'artists.category_id = categories.id');
$this->db->where('id', $id);
$this->db->limit(1);
With Print_R I can see I'm getting all columns (but only 1 id, which is from the categories table instead of artists table) without any table prefix.
You should qualify your columns with a table alias
$this->db->select('a.id as artist_id, c.id as category_id, a.column2,c.column3');
$this->db->from('artists a');
$this->db->join('categories c', 'a.category_id = c.categories.id');
$this->db->where('a.id', $id);
$this->db->limit(1);
If you want to continue using SELECT *
$this->db->select('a.*, c.*, a.id as artist_id, c.id as category_id');
$this->db->from('artists a');
$this->db->join('categories c', 'a.category_id = c.categories.id');
$this->db->where('a.id', $id);
$this->db->limit(1);
Keep in mind, that the LAST duplicate column will be returned. So, a.*,c.* will return c.id as id and c.*,a.* will return a.id as id.
I think to save you trouble and for the future, always use the table in front of the column name.
There is no logic here, when you look for * it means all fields, in Oracle for example you will get all fields with the table in front, i guess in MySQL it doesn't, but if i were you, i would not risk it.