so here is my database for a book store
books : id ,title
category : id, title
book_category : id , book_id, category_id
book_stock : id , book_id , quantity , price
considering all the relations are defined in the model , i can query book_stock it goes something like this
Stock::with('Book')->get();
but what if i want to get stock of a book in the category = 1
i can use use condition on book
Stock::with('Book' , function($q){
$q->where(['title'=>'abc']);
})->get();
but how can i filter related table of book ?
basically i want to get book_id from book_category where category_id = 1 and then use those ids to filter my books finally get stock
ps : i don't want to use query builder
This will return you all books belonging to category=1 with their stock information:
$categoryId = 1;
$books = Book::with('stock')->whereHas('category', function($query) use ($categoryId) {
return $query->where('id', $categoryId);
})->get();
You can do:
Stock::with('Book.stock', 'Book.category')->get();
You can access any number of nested relations within a with statement.
Related question:
Laravel nested relationships
Armin Sam's answer should also be a viable option.
Related
here is my category table data
id
1
2
6
7
when in my post bale I join with this category table
here is my post table sample data
ID = 1,
name = 'hellow'
category id = 4 (i join with category table but selected category is
deleted)
here is my index SQL query (when categy_id match with the category.id) then only its fetch
$post = DB::table('posts)->join('category','posts.category_id','categories.id')-.paginate(10);
for some reason, the selected category can be deleted so I try to get category deleted post data
here is my query
$cpost = DB::table('posts')->join('categories','posts.category_id', '!=' ,'categories.id')->select('post.*')->paginate(5);
but above query duplicate post data based on available category data
i want all post data which are category id is not matched with in category table id how can i get that ?
Try this. Key is the leftJoin instead of default innerJoin (join).
// posts without assigned or existing category
$posts = \DB::table('posts')
->leftJoin('category','posts.category_id','categories.id')
->whereNull('categories.id')
->paginate(10);
why are you doing a join for this? you already have category id stored in your post table.
$cpost = DB::table('posts')->where('category_id','!=', $category_id)->paginate(5);
Just try it:
$cpost = DB::table('posts')
->join('categories','posts.category_id', '=' ,'categories.id')
->select('post.*', 'categories.*')
->whereNotIn('posts.category_id', DB::raw('select id from categories'))
->paginate(5);
I have the following table structure
tables
tbl_items
id
sub_category_id //foreign key
table subcategories
tbl_subcategories
id
category_id
name
table categories
tbl_categories
id
name
As you can see from the above the sub_category_id is a foreign key in products table which relates to the id in the subcategories table. the subcategories table have a category_id which is a foreign key from the categories table
Now i wanted to fetch all items belonging to a certain category.
so i have tried
$categories = Categories::where('id',7)->first();
//from categories get subcategoryid
$allsubcategories = Subcategories::where('category_id',$categories->id)->pluck('id')
$allitems = Items::where('status',1)->wherein('sub_category_id',$allsubcategories)
The above works. but is there a neater way to do this?
define a hasManyThrough relationship in the Category model to the Item model.
// on the Category Model
public function items() {
return $this->hasManyThrough(Items::class, Subcategories::class);
}
then you can access all the items belongs to a particular category
// On your Controller
$category = Categories::where('id',7)->first();
$items = $category->items
official documentation - https://laravel.com/docs/5.7/eloquent-relationships#has-many-through
Well you could probably try using Nested Eager Loading, which should be a little more efficent:
//Assuming the relationships are named subCategories() on Categories model & items() on Subcategories model
$cat = Categories::where('id', 7)
->with('subCategories.items')
->get()
->first();
That should load the category w/ all the subCategories and all the items within each subCategories with the least amount of queries.
Good evening my coder friends,
As the title of this Question says, i have a little bit complex mysql query that i am trying to use query builder in Laravel to write it down, but every time i try to write it i stop when reach to the subquery. i will write down the query and also will let you know what the query will do .
SELECT
brands.name_en as brand_name_en,
brands.name_ar as brand_name_ar,
brands.brand_url as brand_url,
brands.description_ar as description_ar,
brands.description_en as description_en,
categories.name_en as category_name_en,
categories.name_ar as category_name_ar
FROM
brands
INNER JOIN categories ON brands.category_id = categories.id
WHERE
(brands.status = "1")
AND
(
brands.id IN (
SELECT
distinct(items.brand_id)
FROM
items
WHERE
items.in_stock = "1"
GROUP BY
(items.brand_id)
)
)
The query explanation :
I have three tables :
Brand (id,name,category_id)
Categories (id,name,brand_id)
Items (id,brand_id,in_stock,sold_date)
Now i want to do the following :
i want to retrieve (brand name , and the category name ) and sort them based on the highest sales in the last month
This is example on the tables with data in them :
Brands Table
------------
id name category_id
1 googleplay 1
Categories Table
--------------------------
id name brand_id
1 cards 1
items Table
-----------
id brand_id in_stock selling_date
1 1 0 null
1 1 1 2017-02-02 04:04:49
Been trying for almost 2 days but no luck as its really complicated when it reaches the subquery part .
Really hope to find help from you guys . and let me know if you guys need more explanation please , i might forgot something while writing the questions .
Thank you in advance.
If you change your sql a little, you can make it with inner joins:
SELECT brands.name, categories.name
FROM brands
INNER JOIN categories ON brands.category_id = categories.id
INNER JOIN items ON categories.id = items.brand_id
WHERE brands.status = 1 AND items.in_stock = 1
Translating this to Laravel is simple:
\DB::table('brands')
->join('categories', 'brands.category_id', '=', 'categories.id')
->join('items', 'brands.id', '=', 'items.brand_id')
->select('brands.name as brand', 'categories.name as category')
->where('brands.status', 1)
->where('items.in_stock', 1)
->get();
Conceptually speaking, How about we select the items from the item tables for the last month, sort them and fetch the brand and category via a join on that.
It can be written in a single query as follows:
DB::table('items')
->join('brands', 'items.brand_id', '=', 'brands.id')
->join('categories', 'brands.category_id', '=', 'categories.id')
->select('brands.name as brand', 'categories.name as category')
->where('brands.status', 1) // as per your query
->whereRaw(YEAR(items.selling_date) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)) // year condition
->whereRaw(MONTH(date_created) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)) // last month condition
->orderBy('items.in_stock', 'desc') // orderBy the sales
->distinct() // Since you only require brand names and category names, choosing distinct will avoid the need of the GROUP BY eliminating the multiple occurances of a brand in the items table
->get()
I haven't tried running this query, but hope it helps. If I have misunderstood the question feel free to correct me.
I have two tables: categories and videos, I then have a pivot table for these as it's a belongsToMany relationship.
What I'm trying to do is get all of the videos where there isn't a single instance of the video being in one of many categories.
e.g.
Video 1 is in category 1, 2 and 3.
Video 2 is in category 1 and 3.
Video 3 is in category 1.
I want to get the video which is NOT in category 2 or 3, meaning this will return Video 3.
What I've tried so far, which doesn't give the intended result, this is because another row is still found for Video 1 and 2, as they are in Category 1:
Video::whereHas('categories', function($query) {
$query->whereNotIn('category_id', [2,3]);
})->take(25)->get();
The query populated from this is:
select * from `videos` where exists (select * from `categories` inner join
`category_video` on `categories`.`id` = `category_video`.`category_id` where
`videos`.`id` = `category_video`.`video_id` and `category_id` != ? and
`category_id` != ? and `categories`.`deleted_at` is null) and `videos`.`deleted_at`
is null order by `created_at` desc limit 25
You can use Eloquent's whereDoesntHave() constraint to get what you need:
// get all Videos that don't belong to category 2 and 3
Video::whereDoesntHave('categories', function($query) {
$query->whereIn('id', [2, 3]);
})->get();
I have a relational database in this format
Table: posts
Columns: post_id,post_title,post_content
Table: categories
Columns: category_id,category_name
Table: posts_categories
Columns: post_id,category_id
Posts can have multiple categories so i store them in posts_categories using post and category id, when i get results from database using below query, it just display the last category, Is it possible to display all categories otherwise i have to run a separate query, here my code.
$this->db->select("p.*,pc.*,c.*");
$this->db->where('post_id', $id);
$this->db->from('posts AS p');
$this->db->join('posts_categories AS pc', 'pc.post_id = p.post_id', 'inner');
$this->db->join('categories AS c', 'pc.category_id = c.category_id', 'inner');
$q = $this->db->get();
Thanks for any help.
You didn't mention what fields you actually select. However, you can SELECT p.title, c.category_name and after doing your query (mentioned in the question), you should have multiple rows in your result, containing the posts title and a category name for that post.
Now if you want you can group these categories by posts in php, building a new array from the db result.