I'm new at Laravel and have a question about combining 2 JOIN results.
At first, I have the following tables:
videos: id, approved
videos_languages: video_id, language_id, name
Now I do the following:
$arr = Video::join("videos_languages","video_id","=","videos.id")->whereRaw("approved = 0")->get();
Then I pass the array to my view.
I get the values, but now have double results, if one video has more than 1 language. Is it possible, to combine the results of that join with Laravel into one result?
Example:
$arr[0]['id'] = 5;
$arr[0]['approved'] = 0;
$arr[0]['videos_langauges][0] =
{
'name' = ...
}
$arr[0]['videos_langauges][1] =
{
'name' = ...
}
Thank you :)
$arr = Video::distinct()->join("videos_languages","video_id","=","videos.id")->where("approved", 0)->get();
That should clean up duplicates from your results. Also note where() instead of whereRaw().
Related
I am working on a report on which all employees and their salary detail will be fetch according to the departments wise. I have successfully fetch the employees by the department using multidimensional array but now I need to fetch the employees_salary_detail on that employees detail multidimensional array. It means first department->emp_detail->salarydetail. I have successfully fetch the first two part but now i am facing issue on fetching the last array in that emp_detail array.
public function getDepartmentReport(){
$employee = $this->db->select('*')
->from('departments')
->where('project_id', $this->session->userdata('client_id'))->get()->result_array();
$data = array();
foreach($employee as $m => $v){
$v['emp_detail'] = $this->db->select('first_name,employee_code,employees_salary.*')
->from('employees')
->join('employees_salary', 'employees_salary.employee_id = employees.id')
->where('employees.department_id',$v['id'])
->where('employees_salary.month', 'Nov')
->get()->result_array();
$data[] = $v;
foreach($v['emp_detail'] as $m => $s){
$s['salary_detail'] = $this->db->select('*')
->from('employees_salary_detail')->where('employees_salary_detail.salary_id', $s['id'])
->get()->result_array();
$data[] = $s;
}
}
return $data;
}
But now it is creating seperate array for showing salary detail not in that emp_detail array.
I don't know where i am making mistake. please help me to fix this issue.
THANK YOU IN ADVANCE FOR HELPING
Use Join Method to join all three tables in the database on the basis of common keys. I can see you have joined two tables same way you can join multiple tables and create a single array of data.
$qry = $this->db->query("SELECT * FROM product_section INNER
JOIN products ON product_section.ps_prid = products.prid INNER
JOIN wishlist ON wishlist.wish_product_id = products.product_id
INNER JOIN customer ON wishlist.wish_user_id = customer.cust_id
INNER JOIN brands ON brands.brand_id = products.product_brand
WHERE customer.cust_id = '$cid' GROUP BY
product_section.ps_prid");
like this above code
Question first, explanation later:
Insteat of the first array, i want one which looks like the secound array:
echo json_encode($movies);
//WHAT I DO NOT WANT: [{"movie_name":"test1","genre_name":"Action"},{"movie_name":"test2","genre_name":"Drama"},{"movie_name":"test2","genre_name":"Action"}]
//WHAT I WANT: [{"movie_name":"test1","genres":["Action"]},{"movie_name":"test2","genres":["Drama","Action"]}]
So insteat of severals rows with the same value for movie_name but different values for genre_name, i want one row for each movie, where all genre_names are merged into one gernes array;
The solution i wish:
The data is fetched from an database using php and mysqli. This is the SQL query i use and which generates the first array:
SELECT movies.movie_name, genres.genre_name FROM genres
INNER JOIN genre_movie ON genres.id = genre_movie.genre_id
INNER JOIN movies ON movies.id = genre_movie.movie_id;
I am not good with SQL and think there is a query which gets the me the secound array (the one I WANT) right away.
My solution so far:
i actually solved the problem using a php arglorithm, but its kinda complecated and hard if the anything scales or i add new columns:
foreach($myArray as $movie)
{
foreach($newList as $key => $item)
{
if($item['movie_name'] == $movie['movie_name']){
$exists = true;
$position = $key;
}
}
if($exists == true)
{
$newList[$position]['genres'][] = $movie['genre_name'];
$exists= false;
} else {
$newList[] = array('movie_name' => $movie['movie_name'], 'genres' => array($movie['genre_name']));
}
}
Take a look at group_concat: http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_group-concat
I didn't emulate your tables but maybe this is your query:
SELECT movies.movie_name, group_concat(genres.genre_name) FROM genres
INNER JOIN genre_movie ON genres.id = genre_movie.genre_id
INNER JOIN movies ON movies.id = genre_movie.movie_id
GROUP BY movies.movie_name;
Edition
Well, I emulated it now, and yes, it's your query. I would just change:
group_concat(genres.genre_name)
For:
group_concat(distinct(genres.genre_name))
To return only different values.
How can I format a one to many relationship to one 'row' using mysql or php?
Main Table
movie_id name
1 Portland
2 Blazers
Many Table
movie_id actor
1 Brandon
2 Greg
Below is the psudo code I have mapped out. Not sure if there is any thing native to PHP or MYSQl that would be more efficient before I continue. I'm thinking I have two queries. One with the movie information. One with the actor information. Once they are arrays I will loop through to get a single record for each movie with the actors.
movieInfo = = []
actorInfo = = []
Foreach(movieActorId)
If(actorId = movieActorId)
arrayPush(movieInfo[actorArray],actorInfo[name]);
The final array would look like this
movieInfo = array('movie_id' => '1',
'movie_name' => 'porland',
'actor' => array(Brandon,Greg)
);
Maybe this is what you need:
SELECT m.movie_id, m.name AS movie_name, GROUP_CONCAT(a.actor SEPARATOR ',') AS actor
FROM movies m
JOIN actors a ON m.movie_id = a.movie_id
GROUP BY m.movie_id;
// Run query
$movieInfo = array();
while ($array = mysqli_fetch_assoc($result)) {
$array['actor'] = explode(',', $array['actor']);
$movieInfo[] = $array;
}
Confession: a mysql newb requires simple example to locate duplicate rows in somewhat large table. I have searched for and read many other threads with similar titles, but the examples are so complex that I cannot apply them to my basic situation.
A MySQL table has only 5 fields, but there are hundreds of rows. I wish to locate duplicate rows -- I know there is one for sure and wonder if there are others.
Example Row: (rel_id is auto-incrementing, primary key field)
'rel_id' => 1
'host' => 17
'host_type' => 'client'
'rep' => 7
'rep_type => 'cli_mgr'
My approach was to:
1. Read entire table into mysql query
2. row-by-row compare the 4 data fields to those of previous ("done") rows
3. after comparing a "new" row, append it to array of "done" rows
Here is what I have tried. I am sure that there must be a much simpler solution. You will see that I am bogged down in trying to append the "new" row to the array of "done" rows:
$rRels = mysql_query("SELECT * FROM `rels`");
$a = array();
$e = array();
$c1 = 0;
$c2 = 0;
While ($r = mysql_fetch_assoc($rRels)) {
$i = $r['rel_id'];
$h = $r['host'];
$ht = $r['host_type'];
$r = $r['rep'];
$rt = $r['rep_type'];
foreach($a as $row) {
$xh = $row['host'];
$xht = $row['host_type'];
$xr = $row['rel'];
$xrt = $row['rel_type'];
if (($h==$xh) && ($ht==$xht) && ($r==$xr) && ($rt==$xrt)) {
echo 'Found one<br>';
$e[] = $r;
}
$c2++;
}
$a = array_merge(array('rel_id'=>$i, 'host'=>$h, 'host_type'=>$ht, 'rep'=>$r, 'rep_type'=>$rt), $a);
$c1++;
}
echo '<h3>Duplicate Rows:</h3>';
foreach ($e as $row) {
print_r($row);
echo '<br>';
}
echo '<br><br>';
echo 'Counter 1: ' . $c1 . '<br>';
echo 'Counter 2: ' . $c2 . '<br>';
This should do the trick:
SELECT COUNT(*) as cnt, GROUP_CONCAT(rel_id) AS ids
FROM rels
GROUP BY host, host_type, rep, rep_type
HAVING cnt > 1
any "duplicate" records will have a cnt > 1, and the group_concat will give you the ids of the duped records.
Pure no-php solution : to make the copy of the old table (named oldTable) , with no data
create table newTable like oldTable;
Modify the structure to prevent duplicates and add unique key over all 5 columns.
alter table newTable add unique index(rel_id,host,host_type,rep,rep_type );
Then whith sql query copy the rows from oldTable
insert IGNORE into newTable select * from oldTable
In newTable you have only the unique data.
Another option is group by, if you will get the number of duplicate rows use
select concat_ws('_',rel_id,host,host_type,rep,rep_type) as str, count(*)
from oldTable
group by str
You can this query to find all the duplicate rows. Hopefully, it should be easy integrating in your PHP code.
// This will give you all the duplicates
// Self join where all the columns have the same values but different primary keys
SELECT *
FROM rels t1, rels t2
WHERE t1.rel_id != t2.rel_id
AND t1.host = t2.host
AND t1.host_type = t2.host_type
AND t1.rep = t2.rep
AND t1.rep_type = t2.rep_type
Finding duplicates is more easily done in SQL than in PHP.
SELECT GROUP_CONCAT(rel_id)
FROM rels
GROUP BY host, host_type, rep, rep_type HAVING COUNT(rel_id)>1;
This will show the groups of rel_id that point to identical records. The HAVING COUNT(rel_id)>1 clause allows us to skip unduplicated records.
I'm trying to filter some car parts depending on the categories they are related to.
A part can have many categories (in the code they are called tags), so I chose the HABTM relation with a join table.
Filtering works so far, but only with an OR condition with cake using the SQL command IN.
But I'm trying to filter only the parts that have all the selected categories, so I need to use an AND condition on the category array.
Here's the extracted code from the controller:
$this->Part->bindModel(array('hasOne' => array('PartsTagsJoin')));
$params['conditions'] = array('AND' => array('PartsTagsJoin.tag_id' => $selectedCats));
$params['group'] = array('Part.id');
$parts = $this->Part->find('all',$params);
$this->set('parts',$parts);
$selectedCats is an array like this: array(1,2,3,4,5);
The SQL output is:
'SELECT `Part`.`id`, `Part`.`name`, `Part`.`image`, `Part`.`image_dir`, `Part`.`time_created`, `Part`.`time_edited`, `Part`.`user_id`, `Part`.`editor_id`, `Part`.`notice`, `User`.`id`, `User`.`username`, `User`.`password`, `User`.`usergroup_id`, `User`.`realname`, `PartsTagsJoin`.`id`, `PartsTagsJoin`.`part_id`, `PartsTagsJoin`.`tag_id`
FROM `c33rdfloor`.`parts` AS `Part`
LEFT JOIN `c33rdfloor`.`users` AS `User` ON (`Part`.`user_id` = `User`.`id`)
LEFT JOIN `c33rdfloor`.`parts_tags_join` AS `PartsTagsJoin` ON (`PartsTagsJoin`.`part_id` = `Part`.`id`)
WHERE `PartsTagsJoin`.`tag_id` IN (1, 4, 8, 24)'
How can I filter the parts that have every id that is committed through the $selectedCats Array.
Thank you in advance for your help.
I've got it working thanks to this blog post:
http://nuts-and-bolts-of-cakephp.com/2008/08/06/habtm-and-join-trickery-with-cakephp/
It seems to be a little tricky to filter entries with all selected tags:
The key in achieving an AND relation is to get the count of the selected cats and match it with the ones of the query inside the group parameter.
This line did it:
$params['group'] = array('Part.id','Part.name HAVING COUNT(*) = '.$numCount);
In the End the code looked like this (for people interested in a solution):
// Unbinds the old hasAndBelongsToMany relation and adds a new relation for the output
$this->Part->unbindModel(array('hasAndBelongsToMany'=>array('PartsTag')));
$this->Part->bindModel(array('hasOne'=>array(
'PartsTagsJoin'=>array(
'foreignKey'=>false,
'type'=>'INNER',
'conditions'=>array('PartsTagsJoin.part_id = Part.id')
),
'PartsTag'=>array(
'foreignKey'=>false,
'type'=>'INNER',
'conditions'=>array(
'PartsTag.id = PartsTagsJoin.tag_id',
'PartsTag.id'=>$selectedCats
)))));
$numCount = count($selectedCats); // count of the selected tags
// groups the entries to the ones that got at least the count of the selected tags -> here the 'AND' magic happens
$params['group'] = array('Part.id','Part.name HAVING COUNT(*) = '.$numCount);
$parts = $this->Part->find('all', $params); // sends the query with the params
$this->set('tagCategories', $categories);
$this->set('selectedCats', $selectedCats);
$this->Part->recursive = 4;
$this->set('parts',$parts);