I have 3 tables like this below :
Items table
id | name
1 | Laptop
2 | Computer
3 | Tv
Production table
id | date
1 | 2021-10-01
2 | 2021-10-03
3 | 2021-10-30
Detail table
id | production_id| item_id |qty
1 | 1 | 1 | 5
2 | 1 | 3 | 10
3 | 2 | 1 |2
4 | 2 | 2 |3
5 | 2 | 3 |23
And what I'm trying to achieve is like this :
(where Production dateBetween this date and that date)
Items |Sum qty
Laptop | 7
Computer | 3
Tv | 33
How to do this in eloquent way ?
Should I use hasManyThrough relationship ?
Thank you for your kind help.
Since this is concatenation problem, i would not use standard relationships for this. Instead let mysql solve this, by creating a custom query in the ORM.
The strategy is to join all the rows, group it by the name of the product. Sum the quantity and create the where condition for the dates.
$items = Item::select('name', DB::raw('SUM(details.qty) as quantity'))
->join('details', 'items.id', '=', 'details.item_id')
->join('productions', 'productions.id', '=', 'details.production_id')
->whereBetween('productions.date', [now()->subMonth(), now())
->groupBy('details.name')
->get();
You could loop the data like so.
foreach ($items as $item) {
$item->name;
$item->quantity;
}
Related
I am quite new with Laravel and still learning.
Love the application, but find it quite difficult
to find the right way to make a search form.
I have two tables, table1 and table2.
Their structure is something like this:
table1 = id | user_id | data
1 | 1 | x
2 | 2 | y
table2 = id | user_id | sex_id | data
1 | 1 | 1 | a
2 | 2 | 2 | b
3 | 1 | 1 | c
4 | 2 | 1 | d
Now I want to select all the data from table1
where the user_id from table1 has the sex_id 1 in table2.
Would this be possible?
What would be the right way to select from multiple tables in Laravel?
Thank you, your input is highly appreciated.
Have made it work with the join function.
See example below;
# gender search
$get_pages = DB::table('d_pages')
->join('d_user_profiles', function($join) use($gender) {
$join->on('d_user_profiles.user_id', '=', 'd_pages.user_id');
$join->where('d_user_profiles.m_sex_id', '=', $gender);
})
->select('d_pages.id', 'd_pages.user_id', 'd_pages.image_path')
->orderBy('d_pages.like_amount', 'desc')->get();
I am creating a system using Laravel and AngularJS where I assign tasks to users. Multiple tasks has multiple users and vice versa. In the Database, I have this tables:
task:
id | name
task_users:
id | task_id | user_id
users:
id | name
In my view, I display a particular task, using id of task table. I display a list of users (called unassigned users) who are not assigned to that particular task. When that user is assigned, it's name gets removed from the list.
To achieve this, I used this query:
public static function remainingUser($task_id)
{
return \DB::table('users')
->leftjoin('task_users', 'task_users.user_id', '=', 'users.id')
->select('users.id',
'users.name as name'
)
->where('task_id', '!=', $task_id)
->orWhere('task_id', null)
->get();
}
Suppose I have this data
task:
id | name
1 | Task1
2 | Task2
3 | Task3
users:
id | name
1 | User1
2 | User2
3 | User3
4 | User4
5 | User5
6 | User6
7 | User7
8 | User8
9 | User9
10 | User10
task_users:
id | task_id | user_id
1 | 1 | 1
1 | 1 | 2
1 | 1 | 3
1 | 1 | 5
1 | 1 | 6
1 | 1 | 7
1 | 2 | 2
1 | 2 | 4
Now suppose I am displaying task details of task_id = 1 and I want to assign user 4 to this task. So my list of unassigned users should contain all the users who are not assigned this task. My query does not return the required data. I have also tried different conditions in where clause, but I do not get the correct required data. What am I doing wrong?
The issue exists because when you select from Users, you get all users left Joined with a single instance of tasks. So if User1 has Task1 and Task2, only Task1 will be matched here, because it will match User1 to the 1st row found for him within task_users. In order to list the unasigned users, your query would look similar to this:
public static function remainingUser($task_id)
{
return \DB::table('task_users')
->rightJoin('users', 'task_users.user_id', '=', 'users.id')
->select(
\DB::raw("DISTINCT(`users`.`id`)"),
'users.name as name'
)
->where('task_id', '!=', $task_id)
->orWhere('task_id', null)
->get();
}
I have this table (Pickups):
+-----------+------------+-------------+------------+
| worker_id | box_weight | bag_weight | date |
+-----------+------------+-------------+------------+
| 1 | 2 | 5 | 11-07-2018 |
| 1 | 7 | 9 | 11-07-2018 |
| 2 | 8 | 11 | 11-07-2018 |
| 2 | 7 | 12 | 11-07-2018 |
+-----------+------------+-------------+------------+
and I want in Laravel 5.4 Eloquent database engine get the sum of the box_weight and the bag_weight like this:
+-----------+-----------------+-----------------+------------+
| worker_id | sum(box_weight) | sum(bag_weight) | date |
+-----------+-----------------+-----------------+------------+
| 1 | 9 | 14 | 11-07-2018 |
| 2 | 15 | 23 | 11-07-2018 |
+-----------+-----------------+-----------------+------------+
Until now I could only retrieve the sum of a single column not the both in the same call.
Please find the answer bellow, since you didn't mention you want sum of same date per worker id or all dates, I assume only same date, if you want sum of all dates per worker id, remove date from groupBy
Eloquent Query
Pickup::select(['worker_id ','date',DB::raw('sum(box_weight)'),DB::raw('sum(bag_weight)')])
->groupBy('worker_id','date')
->get();
or in Query Builder Approach
DB::table('pickups')
->select(['worker_id ','date',DB::raw('sum(box_weight)'),DB::raw('sum(bag_weight)')])
->groupBy('worker_id','date')
->get();
You're looking for the MySql query or Laravel's QueryBuilder/Eloquent?
I'm assuming you want it grouped by worker_id and not by date, if it's by date, just add date to the groupBy
In the future, show us what you've tried and you're trying to accomplish in more detail
If you're looking for the MySqlQuery, Rom's answer will do just fine
SELECT worker_id, sum(box_weight), sum(bag_weight), date
FROM pickups
GROUP BY worker_id
If you're going from the Eloquent model:
//Assuming Pickup is your model name
Pickup::selectRaw('worker_id, sum(box_weight), sum(bag_weight), date')
->groupBy('worker_id')->get();
Using DB
DB::table('pickups')->selectRaw('worker_id, sum(box_weight), sum(bag_weight), date')
->groupBy('worker_id')->get();
//Or even
DB::select(DB::raw('SELECT worker_id, sum(box_weight), sum(bag_weight), date
FROM pickups
GROUP BY worker_id');
This will give you a collection of pickups, place toArray() at the end of the query if you wish to convert it to an array
The reason behind selectRaw is due to not being able to use ->sum() with ->select(). It works just fine for the sum of a column, not for multiple output and the same goes for select, as it can't relate sum(column) as a column
I have two tables in a MySQL database like this:
User:
userid |userid | Username | Plan(VARCHAR) | Status |
-----------+------------+--------------+---------------+---------+
1 | 1 | John | 1,2,3 |1 |
2 | 2 | Cynthia | 1,2 |1 |
3 | 3 | Charles | 2,3,4 |1 |
Plan: (planid is primary key)
planid(INT) | Plan_Name | Cost | status |
-------------+----------------+----------+--------------+
1 | Tamil Pack | 100 | ACTIVE |
2 | English Pack | 100 | ACTIVE |
3 | SportsPack | 100 | ACTIVE |
4 | KidsPack | 100 | ACTIVE |
OUTPUT
id |userid | Username | Plan | Planname |
---+-------+----------+------------+-------------------------------------+
1 | 1 | John | 1,2,3 |Tamil Pack,English Pack,SportsPack |
2 | 2 | Cynthia | 1,2 |Tamil Pack,English Pack |
3 | 3 | Charles | 2,3,4 |English Pack,Sportspack, Kidspack |
Since plan id in Plan table is integer and the user can hold many plans, its stored as comma separated as varchar, so when i try with IN condition its not working.
SELECT * FROM plan WHERE find_in_set(plan_id,(select user.planid from user where user.userid=1))
This get me the 3 rows from plan table but i want the desired output as above.
How to do that.? any help Please
A rewrite off your query what should work is as follows..
Query
SELECT
all columns you need
, GROUP_CONCAT(Plan.Plan_Name ORDER BY Plan.planid) AS Planname
FROM
Plan
WHERE
FIND_IN_SET(Plan.plan_id,(
SELECT
User.Plan
FROM
user
WHERE User.userid = 1
)
)
GROUP BY
all columns what are in the select (NOT the GROUP_CONCAT function)
You also can use FIND_IN_SET on the ON clause off a INNER JOIN.
One problem is that the join won't ever use indexes.
Query
SELECT
all columns you need
, GROUP_CONCAT(Plan.Plan_Name ORDER BY Plan.planid) AS Planname
FROM
User
INNER JOIN
Plan
ON
FIND_IN_SET(Plan.id, User.Plan)
WHERE
User.id = 1
GROUP BY
all columns what are in the select (NOT the GROUP_CONCAT function)
Like i said in the comments you should normalize the table structures and add the table User_Plan whats holds the relations between the table User and Plan.
I have a table which have category_id and parent_category_id. How I can get 1 category and 5 sub category by using SQL query.
Suppose table name is : Category
----------------------------------------------------------------
Category ID | Parent ID | Name
----------------------------------------------------------------
1 | NULL | Electronics
2 | 1 | Computer
3 | 1 | Calculator
4 | 1 | Mobile
5 | NULL | Four Wheeler
6 | 5 | Cars
7 | 5 | Trucks
8 | 5 | Jeep
9 | 5 | Van
Since MySQL does not support recursive queries/CTEs, you will have to emulate that (which is not, say, straightforward).
Here's an excellent tutorial on the subject:
http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/
I will have the decency of not copying the code here :)
For SQL Server, you can use the WITH query to get the complete path (more here http://msdn.microsoft.com/en-us/library/ms175972.aspx).