I'm having problems with getting correct data in a three-way join.
EDIT: Sample table structure
Jobs Table
id | name | country | country_slug | city
1 | Job1 | Canada | canada | Ontario
2 | Job2 | South Africa | south-africa | Durban
Cheers Table
id | rep | jobs_id
1 | 14 | 2
2 | 9 | 1
3 | 12 | 2
4 | 23 | 1
Categories Table
id | name
1 | PHP
2 | Laravel
3 | Javascript
4 | Go
category_job pivot Table
id | category_id | job_id
1 | 2 | 1
2 | 2 | 2
3 | 1 | 1
4 | 3 | 2
5 | 4 | 1
Here is an example of what my models look like:
Job
public function categories(){
$this->belongsToMany(Category::class)
}
public function cheers(){
$this->hasMany(Cheer::class)
}
Category
public function jobs() {
$this->belongsToMany(Job::class)
}
Cheer
public function job() {
return $this->belongsTo(Job::class);
}
This is what I'm trying to achieve:
Group jobs by country
Get count of how many jobs are in each country (job_count)
Get count how many cities (distinct) in each group (city_count)
Sum (rep) in cheers relation table for each group
Get the most popular category for each country group via Categories relationship
This is my code so far:
$result = Job::
selectRaw(
"jobs.country,
jobs.country_slug,
COUNT('jobs') as job_count,
COUNT(DISTINCT city) as city_count,
SUM(rep) as cheer_rep",
)
->join('cheers', 'cheers.jobs_id', '=', 'jobs.id')
->orderByDesc('cheer_rep')
->groupBy('jobs.country', 'jobs.country_slug')
->get();
Here are my problems;
The job count is wrong because the join clause adds more results due to the hasMany relationship.
I can't seem to wrap my head around grouping the categories and getting the most occurring (popular) category.
Sample result
[
{
"country": "Canada",
"country_slug": "canada",
"job_count": 23,
"cities": 5,
"cheer_rep": "35000"
},
{
"country": "South Africa",
"country_slug": "south-africa",
"job_count": 9,
"cities": 2,
"cheer_rep": "700"
},
]
Any help would be highly appreciated. Also, if there's an eloquent way of achieving this, I'd appreciate that too.
Eloquent way:
Job::with('cheers')
->select(DB::raw('count(country) as job_count, country'),
DB::raw('count(city) as city_count, city')
)
->orderByDesc('cheers.cheer_rep')
->groupBy('country', 'country_slug')
->get();
Note: Not tested, as you did not provided DB schema.
Related
Basically i have two tables. answers and choices . In my choices table, I got a column choices.value which is has values 0-4. My current query like this
$answers = \DB::table('answers')
->join('choices','answers.choice_id','=','choices.choice_id')
->select('answers.user_id','choices.choice_id','choices.choice','choices.value')
->where('answers.user_id',\Auth::user()->id)
//->groupBy('answers.user_id')
->get();
My current response is like this
"user_id": 2,
"choice_id": 2,
"choice": "I feel discourated about the future",
"value": 1
},
{
"user_id": 2,
"choice_id": 2,
"choice": "I don't enjoy things the way I used to",
"value": 1
},
{
"user_id": 2,
"choice_id": 2,
"choice": "I feel guilty a good part of time",
"value": 1
how do i add the values so that my result will be like this
"user_id":2,
"total_score":3
I tried doing DB::raw(SUM(choices.values)as score) but i get a large amount. I guess its adding all the choices values from the choices table and not in the answers.
My answers db which i only select the answers of the user = 2. I limit to 5
+---------+-------------+-----------+
| user_id | question_id | choice_id |
+---------+-------------+-----------+
| 2 | 1 | 2 |
| 2 | 2 | 2 |
| 2 | 3 | 2 |
| 2 | 4 | 2 |
| 2 | 5 | 2 |
+---------+-------------+-----------+
My choices table, I only select questions 1 and 2 and their choices.
+-----------+-------------+--------------------------------------------------------------+-------+
| choice_id | question_id | choice | value |
+-----------+-------------+--------------------------------------------------------------+-------+
| 1 | 1 | I do not feel sad | 0 |
| 2 | 1 | I feel sad | 1 |
| 3 | 1 | I am sad all the time and I can't snap out of it | 2 |
| 4 | 1 | I am so sad and unhappy that I can't stand it | 3 |
| 1 | 2 | I am not particularly discouraged about the future | 0 |
| 2 | 2 | I feel discourated about the future | 1 |
| 3 | 2 | I feel I have nothing to look forward to | 2 |
| 4 | 2 | I feel the future is hopeless and that things cannot improve | 3 |
+-----------+-------------+--------------------------------------------------------------+-------+
Also i want to make a new table named scores and the columns will be the result of what i want. I want to add the choices.values in the answer in every answers.user_id so that when i view the scores table, it will display the total score in every user or when the user finished answering all 21 questions because i only got 21 items it will automatically add in the scores table. Could I possibly do that?. Is it okay to add a value in the answers table based in the choice_id? That is what im thinking but I think its redundant since the choice_id is there already. Thanks in advance.
PS: Tried writing these queries but always get 441 which is the total value of all the choices in the choices table
SELECT answers.user_id,choices.choice_id,choices.value,COALESCE(sum(choices.value),0) as score FROM
`answers` JOIN `choices` ON choices.choice_id = answers.choice_id where
answers.user_id = 2
SELECT answers.user_id,choices.choice_id,choices.value,SUM(choices.value),0 as score FROM `answers`
join choices on choices.choice_id = answers.choice_id
where answers.user_id = 2
SELECT answers.user_id,choices.choice_id, sum(choices.value) from answers
JOIN `choices` ON choices.choice_id = answers.choice_id
group by answers.user_id
Currently you are only matching to a choice but you need to match the choice as well as the question.
I found this after seeng each choices.question_id had choices 1, 2, 3 and 4 in a slack conversation. I didn't know until I actually saw a screenshot of the choices table.
$answers = \DB::table('answers')
->join('choices', function ($q) {
$q->on('answers.choice_id','=','choices.choice_id')
->on('answers.question_id', '=', 'choices.question_id');
})
->select('answers.user_id',\DB::raw('sum(choices.value) as total'))
->groupBy('answers.user_id')
->get();
use group by maybe it will help
$answers = \DB::table('answers')
->join('choices','answers.choice_id','=','choices.choice_id')
->select('answers.user_id',DB::raw('count(*) as total'))
->where('answers.user_id',\Auth::user()->id)
->groupBy('answers.user_id')
->get();
I have four tables
jobposts:
id | user_id | cat_id | job_title
1 | 1 | 1 | job 1
2 | 1 | 2 | job 2
3 | 2 | 3 | job 3
4 | 1 | 3 | job 4
categorymasters:
id | category_name
1 | cat1
2 | cat2
3 | cat3
4 | cat4
lastsubcategoryselectedbycompanies:
id | jobposts_id | lastsubcategorymasters_id
1 | 1 | 1
2 | 1 | 2
3 | 2 | 3
4 | 1 | 3
lastsubcategorymasters:
id | LastSubCategoryName
1 | lastsubcat1
2 | lastsubcat2
3 | lastsubcat3
4 | lastsubcat4
jobposts have unique rows.
lastsubcategoryselectedbycompanies is a mapping of jobposts and lastsubcategorymasters.
Now assume some user is logged in with their credentials (EX: take user_id 1 in jobposts). Now I need to show LastSubCategoryName in a comma separated list from the lastsubcategorymasters table, grouped by the jobposts, lastsubcategoryselectedbycompanies and lastsubcategorymasters tables.
allpostedjob.blade.php is:
#foreach($jobposteddetails as $jobposteddetail)
<tr>
<td>{{ $jobposteddetail->job_title }}</td>
</tr>
#endforeach
cotroller is:
public function index()
{
$user = Auth::user();
$jobposteddetails = jobpost::with('categorymaster')->where('user_id', '=', $user->id)->get();
return view('jobprovider.allpostedjob', compact('user','jobposteddetails'));
}
jobpost.php model is:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class jobpost extends Model
{
function categorymaster()
{
return $this->belongsTo(categorymaster::class, 'cat_id');
}
}
It is working proper.
But I also need to show LastSubCategoryName grouped by the tables jobposts, lastsubcategoryselectedbycompanies and lastsubcategorymasters.
function lastsubcategory()
{
return $this->belongsTo(lastsubcategoryselectedbycompanies::class);
}
It is not working. How can I fetch my result?
I am not very skilled at applying complex queries with eloquent, I prefer to use DB query builder with the join method
https://laravel.com/docs/5.8/queries
I am new to Laravel and Eloquent and i am trying to create a football game plan.
For now i have 4 tables (with some example entries):
teams (all teams)
+---------+-----------+
| team_id | team_name |
+---------+-----------+
| 1 | Arsenal |
| 2 | Chelsea |
+---------+-----------+
competition (all competitions)
+----------------+------------------+
| competition_id | competition_name |
+----------------+------------------+
| 1 | Premier League |
+----------------+------------------+
schedule (schedule to the competitions)
+----+----------------+----------+--------------+--------------+-----------+-----------+
| id | competition_id | matchday | home_team_id | away_team_id | home_goal | away_goal |
+----+----------------+----------+--------------+--------------+-----------+-----------+
| 1 | 1 | 1 | 1 | 2 | 3 | 2 |
| 2 | 1 | 2 | 2 | 1 | 0 | 3 |
+----+----------------+----------+--------------+--------------+-----------+-----------+
schedule_teams (matches the schedule teamid with the teams id over the competition_id and the schedule_team_id)
+----+------------------+----------------+----------+
| id | schedule_team_id | competition_id | teams_id |
+----+------------------+----------------+----------+
| 1 | 1 | 1 | 1 |
| 2 | 2 | 1 | 2 |
+----+------------------+----------------+----------+
And here are my current classes:
Schedule.php
public function competition()
{
return $this->belongsTo(Competition::class, 'competition_id', 'competition_id');
}
Competition.php
public function schedule()
{
return $this->hasMany(Schedule::class, 'competition_id', 'competition_id');
}
With
$id = \request('competition_id');
$schedule = Schedule::where('competition_id', $id)->with('competition')->get();
i get the schedule with the home and away id's from schedule.
The question now is, how can i get the entries from the teams table over the schedule_teams table to a specifiy home and away id, also for example home_team_id = 1:
home_team_id (=1) -> schedule_team_id (=1) and competition_id (=1) -> teams (Arsenal)
I want the data from schedule and the associated teams in a collection to output in a blade.
can anyone help or give me improvement tips for a football database?
You should make use of the hasManyThrough relationship.
If you create say Schedule\Team, and then have that like the following.
public function schedule() {
$this->belongsTo(Schedule::class, 'schedule_id');
}
public function team() {
$this->belongsTo(Team::class, 'team_id');
}
Now in your Schedule class, you can have the following.
public function teams() {
$this->hasManyThrough(Team::class, Schedule\Team::class, 'schedule_id');
}
It should also be noted, that you don't need competition_id in your schedule team. Since a team belongs to a schedule, which belongs to competition, you can get it like that.
If you also want your Team to know about its schedules, you can add this to Team.
public function schedules() {
return $this->hasManyThrough(Schedule::class, Schedule\Team::class);
}
You Schedule\Team class becomes essentially, a glorified representation of a pivot table, but having it as a model, allows you to expand upon it in the future. It also helps keep everything neat.
Hope that makes sense.
Let say I have tables like the following:
order
order_id | customer_name | delivery_address
1 | David | ABC Road, DEF district
...........Some other record ..............
order_dish
order_id | dish_id | dish_name
1 | 1 | chicken wing
1 | 2 | meat pie
1 | 3 | onion ring
...........Some other record ..............
dish_ingredient
dish_id | ingredient
1 | chicken wing
1 | salt
1 | oil
2 | pork meat
2 | flour
3 | onion
...........Some other record ..............
In Laravel 5, if I want to get all dishes of an order, I can do:
$order = Order::hasMany('App\OrderDish', 'order_id')->get();
Is there a way I can get all ingredients needed for an order in one line?
Yes. The "has-many-through" relationship provides a convenient shortcut for accessing distant relations via an intermediate relation. You define it using hasManyThrough() method of your model.
First, define the relation in your Order model:
class Order extends Model {
public function ingredients() {
return $this->hasManyThrough('App\DishIngredient', 'App\OrderDish', 'order_id', 'dish_id');
}
}
With such a relation defined, you'll be able to get ingredients for given order with:
$ingredients = $order->ingredients;
I have two table:
Name
id | name | city_id
1 | aaa | 1
2 | vvv | 2
3 | ddd | 2
4 | sss | 3
5 | dds | 1
etc
City:
id | name
1 | London
2 | NY
3 | Boston
etc
how can i get City and count:
name_city | count
London | 2
NY | 2
Boston | 1
In City table:
$q = $this->createQuery('a')
->leftJoin('a.Name n')
->select('a.name_city as name_city, sum(n.city_id) as sum');
return $q->execute();
but this is wrong.
You should use count() instead of sum(), and plus, you need a group by.
You do not appear to have a FROM clause, the object type is not specified for the a entity.
Also, read the aggregate values section in the documentation.
this post was kinda helpful but I though that I would add a little more details for anyone looking to join 2 tables and with an aggregate count.
e.g. this post (http://stackoverflow.com/questions/7837671/mysql-join-tables-and-count-instances) but in doctrine.
Using the example above the query would be (doctrine 2.0):
$q = $this->em->createQueryBuilder('a')
->select('a.name_city as name_city, count(n.city_id) as sum');
->from('city','a')
->leftJoin('a.Name n')
->groupBy('n.id')
->orderBy('sum')
$query = $qb->getQuery();
echo $qb->getDql(); // if you want to see the dql created
$result = $query->getResult();