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.
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
SELECT i.itemsname
, i.itemsprice
, i.itemsdescrip
, c.catname
, c.catdes
, c.status
, c.collapse
, c.catid
FROM items i
LEFT
JOIN categories c
ON c.catid = i.catid
WHERE i.restid
AND c.restid =12
GROUP
BY c.catid
that is my query at the moment but I would like to have something like this....
but this is what I'm getting:
Ok, I lied in the comments, so With PDO (haven't tested it)
$stmt = $PDO->prepare('SELECT
categories.catname,
items.itemsname,
items.itemsprice,
items.itemsdescrip,
categories.catdes,
categories.status,
categories.collapse,
categories.catid
FROM items
LEFT JOIN categories ON items.catid=categories.catid
WHERE items.restid AND categories.restid = :restid');
$stmt->execute([':restid' => 12]);
$data = $stmt->fetchAll(\PDO::FETCH_GROUP);
foreach($data as $catname => $rows){
//echo group html stuff
//echo "<dl>";
//echo "<dt>$catname</dt>".;
foreach($rows as $row){
//echo row data stuff
// echo "<dd> {stuff} </dd>";
}
//echo "</dl>";
}
I'll leave the html up to you. But as I said you want a data structure like this
[
'BREAKFASTS' => [
0 => [ name => "wimpy hamburger", description => "bla bla", price => "$100,000"],
1 => [ ... ]
],
'SINGLE BURGERS' => [ ...]
]
note that the first field after "SELECT" is by default the field used by FETCH_GROUP
See in this way, the first foreach can output the title of the category, which is BREAKFASTS for example. Then the inner foreach can do the individual rows in the table.
Personally I would use a dl, dt, dd tag setup as my structure (hinted in the comments, i really am to lazy today to code all the html, <sigh>)
https://www.w3schools.com/tags/tag_dt.asp
UPDATE
You may want to check your query
...
WHERE
items.restid AND ...
Seems to be flawed, just saying. I saw this while optomizing the query for sorting.
SELECT
c.catname,
i.itemsname,
i.itemsprice,
i.itemsdescrip,
c.catdes,
c.status,
c.collapse,
c.catid
FROM
(
SELECT c0.catid FROM categories AS c0 WHERE c0.restid = :restid SORT BY c0.catname
) AS t
JOIN
categories AS c ON t.catid=c.catid
LEFT JOIN
items AS i ON items.catid=categories.catid
WHERE
items.restid = ? //< this is the error/omission/strangeness i pointed out above.
So a few things to note, first you should base the query off the categories, as an empty category should be shown, while an item without a category will blow it all to bits ( basically, ie how can you group them by the category if they have none ) You'll wind up with some hodgepoge of items with no category at the end, of course based on your example I'm assuming a Many to One relationship. For example One category can have Many items, and Many items can belong to a category. (it's probably more ideal to do a Many to Many, but that's another story for another day)
The reason the above query is more optimized is the inner query, creates only a small temp table using the catid, And sorts on just the data from the cat table and only the data that is pulled by the where.
Then as we move to the outer query, they basically inherent the sort from the join, and we can pull the rest of the data from that. It's typically about 2-10x faster this way (of course I haven't test this particular query) in theory. Of course this is a bit more complex/advanced query and is optional, but it should improve sort performance if my mind is in the right place tonight... lol
Also I abbreviated your table names (alias), as I said I am lazy like that. Sadly my answers are always so long, dont ask me how I see all these issues, it's just experience or how my dyslexic brain works?
Lastly, if you really must use mysqli, you can manually group them with something like this.
$data = [];
while(false !== ($row = $res->fetch_assoc())){
$key = $row['catname'];
if(!isset($data[$key])) $data[$key] = [];
$data[$key][] = $row;
}
It's all so prosaic (common place, non-poetic) at this point for me.
Good luck.
$cat = mysqli_query($connect, "SELECT
categories.catname,
items.itemsname,
items.itemsprice,
items.itemsdescrip,
categories.catdes,
categories.catid
FROM items
LEFT JOIN categories ON items.catid=categories.catid
WHERE items.restid AND categories.restid = 12");
if($cat === FALSE) {
die(mysqli_error());
}
$data = [];
while ($rowb = mysqli_fetch_array($cat)) {
$key = $rowb['catname'];
if(!isset($data[$key])) $data[$key] = [];
$data[$key][] = $rowb;
foreach($data as $catname => $rowbs){
echo "
<dl><button class='accordiontry'><dt>$catname</dt></button>";
<div class='panel1'>
foreach($rowbs as $rowb){
echo"<div class='rmenu'>
<dd><span class='item'>{$rowb['itemsname']}</span>
<span class='price'>£{$rowb['itemsprice']}</span><br>
<span class='des'>{$rowb['itemsdescrip']}</span> ";
}
echo"</div></dd>
</div></dl>";
}
}
}
I have got the following code to find the similar keywords in body of a text and display the related links with same keyword.
But the problem is for example if two keywords are in row 2 body, Row 2 displays two times but I need the row 2 is displayed once. I tried SELECT DISTINCT but it does not work in foreach loop correctly.
$tags2=explode(",",$tags);
foreach ($tags2 as $i) {
$cat_sqlii="SELECT DISTINCT id, source,title,summary,newsText,photo,mainphoto,link,Date,tags FROM newxtext WHERE (newsText LIKE '%$i%')";
$cat_sql_queryii=mysqli_query($con,$cat_sqlii);
$cat_sql_rowii=mysqli_fetch_assoc($cat_sql_queryii);
do{
echo $cat_sql_rowii['id'].'<br/>';
}while($cat_sql_rowii=mysqli_fetch_assoc($cat_sql_queryii));
}
Just do one query that tests for any of the tags using OR.
$patterns = array();
foreach ($tag in explode(',', $tags)) {
$patterns[] = "newstext like '%$tag%'";
}
$where = implode(' OR ', $patterns);
$cat_sqlii="SELECT id, source,title,summary,newsText,photo,mainphoto,link,Date,tags
FROM newxtext
WHERE ($where)";
$cat_sql_queryii=mysqli_query($con,$cat_sqlii);
while ($cat_sql_rowii = mysqli_fetch_assoc($cat_sql_queryii)) {
echo $cat_sql_rowii['id'].'<br/>';
}
Another approach could be using a temporary table receiving the results for each iteration and querying that table in the end:
mysqli_query($con, "CREATE TEMPORARY TABLE tmpSearchResults(id int primary key) ENGINE=Memory");
$tags2=explode(",",$tags);
foreach ($tags2 as $i) {
$insertToTemp ="INSERT INTO tmpSearchResults
SELECT id
FROM newxtext
WHERE (newsText LIKE '%$i%')";
mysqli_query($con,$insertToTemp);
}
$queryFromTemp = "SELECT DISTINCT n.id, n.source,n.title,n.summary,n.newsText,n.photo,n.mainphoto,n.link,n.`Date`,n.tags
FROM tmpSearchResult r
JOIN newxtext n
WHERE r.id = n.id";
$resultSet = mysqli_query($con,$queryFromTemp);
while($data = mysqli_fetch_assoc($resultSet)){
// ... process here
}
mysqli_free_result($resultSet);
When you close the connection, the temporary table will be dropped automatically.
If you expect huge search results, consider using another storage engine than MEMORY for the temptable.
Let's say i have a query with quite a number of joins and subqueries in one php file that handles queries.
Nb: i put an example of what $query looks like at the bottom
$query = query here;
if ($query) {
return $query->result();
} else {
return false;
}
}
Then in my php file that handles the html, i have the usual foreach loop with some conditions that require making other queries e.g;
Note: result houses object $query->result().
foreach ($results as $item) {
$some_array = array();
$some_id = $item->id;
if ($some_id != 0) {
//id_return_other_id is a function that querys a db table and returns the specified column in the same table, it returns just one field
$other_id = id_return_other_id($some_id);
$some_query = another query that requires some joins and a subquery;
$some_array = the values that are returned from some_query in an array
//here i'm converting obj post into an array so i can merge the data in $some_array to item(Which was converted into an array) then convert all of it back into an object
$item = (object)array_merge($some_array, (array)$item);
}
//do the usual dynamic html stuff here.
}
This works perfectly but as i don't like the way i'm doing lot's of queries in a loop, is there a way to add the if $some_id != 0 in the file that handles queries?
I've tried
$query = query here;
//declaring some array as empty when some_id is 0
$some_array = array();
if ($query) {
if ($some_id != 0) {
//same as i said before
$other_id = $this->id_return_other_id($some_id);
$some_query = some query;
$some_array = array values gotten from some query;
}
$qresult = (object)array_merge($some_array, (array)$query->result);
return $qresult;
} else {
return false;
}
}
This doesn't work for obvious reasons, does any one have any ideas?
Also if there's a way to make these conditions and queries in the $query itself i'd love you forever.
Ps: A demo query would be something like
$sql = "SELECT p.*,up.*,upi.someField,etc..
FROM (
SELECT (another subquery)
FROM table1
WHERE table1_id = 3
UNION ALL
SELECT $user_id
) uf
JOIN table2 p
ON p.id = uf.user_id
LEFT JOIN table3 up
ON .....
LEFT JOIN table4
ON ....
LEFT JOIN table5
ON ....
And so on..etc..
ORDER BY p.date DESC";
$query = mysql_query..
It seems like you just need to run two queries in your query file. The first query would get a broad set of what you’re looking for. The second query would query an id that’s in the result and perform a new query to get any details about that particular id. I use something similar to this in the customer search page for my application.
$output = array();
$query1 = $this->db->query("SELECT * FROM...WHERE id = ...");
foreach ($query->result_array() as $row1)
{
$output[$row1['some_id']] = $row1;
$query2 = $this->db->query("SELECT * FROM table WHERE id = {$row1['some_id']}");
foreach ($query2->result_array() as $row2)
{
$output[$row1['some_id']]['data_details'][$row2['id']] = $row2;
}
}
Then in your page that displays html, you’ll just need two foreaches:
foreach($queryresult as $key=> $field)
{
echo $field['some_field'];
foreach($child['data_details'] as $subkey => $subfield)
{
echo $subfield['some_subfield'];
}
}
I know you’re using objects, but you could probably convert this to use that format. I hope this makes sense/helps.
use this
if ($some_id !== 0) {
instead of
if ($some_id != 0) {
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to fetch result from MySQL row with multiple same-name columns with PHP?
I have two tables, and they share similar column names.
Query is:
SELECT a.name,b.name
FROM tablea a
JOIN tableb b ON a.id = b.id
Results are put into an array:
while ($row = mysql_fetch_array($results)){
$aname = $row['name'];
}
Once I added in that second table I noticed the $aname was using tableb's data.
Question(s): How can I store both name columns, $row['a.name'] does not work. My guess is maybe I need to alias each result in the query. Any suggestions? Should I same avoid giving the column names in the future?
I know mysql_* is deprecated. Save your energy.
Your guess was right. You need to create an ALIAS for the columns so you can fetch it uniquely,
SELECT a.name Name1, b.name Name2
FROM tablea a
JOIN tableb b ON a.id = b.id
then you can now call
$row['Name1']
There is a way.
mysql_field_table() will tell you a result set field's name given the $result handle and ordinal position. In conjunction with mysql_field_name(), that should be everything you need:
// Fetch the table name and then the field name
$qualified_names = array();
for ($i = 0; $i < mysql_num_fields($result); ++$i) {
$table = mysql_field_table($result, $i);
$field = mysql_field_name($result, $i);
array_push($qualified_names, "$table.$field");
}
You could wrap this into your own mysql_fetch_qualified_array function, for example, to give you an associative array keyed on "table.field":
function mysql_fetch_qualified_array($result) {
...
// caching $qualified_names is left as an exercise for the reader
...
if ($row = mysql_fetch_row($result)) {
$row = array_combine($qualified_names, $row);
}
return $row;
}