missing column data when retrieving rows from a JOIN query - php

In php and mysql I use a join query on several tables. Each table has the field name title. I want to get the value of title from each JOINed table, but when I retrieve each row of my result set with php, I only get the last value of title, This is my query.
SELECT UC.user_id,
UC.courses_id,
UC.semester_id,
UC.batch_id,
UC.department_id,
U.title,
U.firstname,
U.lastname,
B.title ,
CO.title,
SE.title,
DEP.title
FROM tbl_user_courses AS UC
INNER JOIN tbl_user AS U ON UC.user_id = U.id
INNER JOIN tbl_batch AS B ON UC.user_id = B.id
INNER JOIN tbl_courses AS CO ON UC.user_id = CO.id
INNER JOIN tbl_semester AS SE ON UC.user_id = SE.id
INNER JOIN tbl_departments AS DEP ON UC.user_id = DEP.id
where UC.trash=0
order by UC.user_id desc
Its php code
<?php
if($rec)
foreach( $rec as $value => $k){
?>
<?php echo $k['title'];
<?php echo $k['title'];?>
<?php echo $k['title'];?>
<?php echo $k['title'];?>
}
Now How can i get each table title its a field name.

You can give the fields an alias, by adding AS <alias> after the field.
SELECT UC.user_id,
UC.courses_id,
UC.semester_id,
UC.batch_id,
UC.department_id,
U.title as user_title,
U.firstname,
U.lastname,
B.title AS batch_title,
CO.title AS course_title,
SE.title AS semester_title,
DEP.title AS department_title
FROM tbl_user_courses AS UC
INNER JOIN tbl_user AS U ON UC.user_id = U.id
INNER JOIN tbl_batch AS B ON UC.user_id = B.id
INNER JOIN tbl_courses AS CO ON UC.user_id = CO.id
INNER JOIN tbl_semester AS SE ON UC.user_id = SE.id
INNER JOIN tbl_departments AS DEP ON UC.user_id = DEP.id
where UC.trash=0
order by UC.user_id desc
If you run this query, you can use the aliases instead of the field name, so use $k['department_title'] to get the name of the department.
I think that 'title' is a rather odd term to use for the name of department or course, but if they would all be named 'name' you would have the same issue again. :D
By the way, you could use a naming convention to reduce collisions like this. Just like you have department_id (and not just id) you could also use department_name or just department. Still, it's good to know about aliases, because you will need them sooner or later.

When you use fetch_assoc() functions in PHP to retrieve rows from your result set, if some of your columns have the same name you'll lose data. You have, as you know, a whole bunch of columns called title.
You want something like this, putting aliases on some of your result set columns so they don't all have the same name.
These aliases don't change the names of columns in your tables. They change the names of the columns in the results of your query only. When you say
SELECT title AS user_title
it fetches the column named title from the table, but then gives it the name user_title in the result set.
Try this:
SELECT UC.user_id, UC.courses_id, UC.semester_id, UC.batch_id, UC.department_id,
U.title AS user_title,
U.firstname, U.lastname,
B.title AS batch_title,
CO.title AS course_title,
SE.title AS semester_title,
DEP.title AS department_title
...
Then, in php, use code like this....
<?php echo $k['user_title'];
<?php echo $k['batch_title'];?>
<?php echo $k['course_title'];?>
<?php echo $k['semester_title'];?>
<?php echo $k['department_title'];?>
Alternatively, you can, if you're using PDO, fetch each row of your result set into a numbered rather than associative array.
$sth = $dbh->prepare("/*YOUR ORIGINAL QUERY8?") || die "prepare failed";
$sth->execute() || die "execute failed";
while ( $k = $sth->fetch( PDO::FETCH_NUM ) ) {
<?php echo 'batch title: ';echo $k[8];?>
<?php echo 'course title: ';echo $k[9];?>
/* etcetera */
}
This works because it fetches the columns of each row in your result set into a numerically indexed array ( 0 .. n) rather than an associative array.
You can also, in the obsolete mysql API, get the same effect with
while ($k = mysql_fetch_array($resultset, MYSQL_NUM) ) {
/* handle the row */
}

Related

Select Mysql Query inside echo of another query

Hello I would like to know how I can realizes query selection inside echo of already processed query.
This is my firs Mysql Query
SELECT * FROM cursos_modulos
foreach($result as $row)
{
$id = $row['id'];
echo"
Here where the echo goes I have to make the other query which is:
SELECT COUNT(users.userID)
FROM users
INNER JOIN subscriptions
ON users.userID = subscriptions.user_id
WHERE subscriptions.curso_id = $id
and at the end to put the result of this query
foreach($result as $rowc)
.$rowc[0]."};
Any help how I can achive this goal will be very welcome. Question is simple. First Select Selects the Cours with it's unique ID. which ID have to be used in the second, third and else... queries. Which queries are like the second one. So First Select Course and then Select different parameters from this course based on this ID. at the end dump results of each of the selections with different indications"
Do it all in one query:
SELECT c.*, count(s.curso_id) as count
FROM cursos_modulos AS c
LEFT JOIN subscriptions AS s ON s.curso_id = c.id
LEFT JOIN users AS u ON u.userID = s.user_id
The LEFT JOIN is needed to get 0 for the count if there are no matching rows in subscriptions.
To include a second count of approved subscriptions:
SELECT c.*, count(s.curso_id) as count, SUM(IF(s.approved = 'approved', 1, 0)) AS count_approved
FROM cursos_modulos AS c
LEFT JOIN subscriptions AS s ON s.curso_id = c.id
LEFT JOIN users AS u ON u.userID = s.user_id

PHP SQL how the get the exact count from a table

I have two tables with the following columns:
FAMILY - id, ...
PRODUCTS - id, idfamily, type, ...
FAMILY & PRODUCTS are connected with family.id = products.idfamily.
I'm doing pagination over families with filters based on products types, so I'm trying to get the exact count of FAMILY containing almost one product with a specific type.
First query is ok, I get all the families:
if (!isset($_GET['type']) || $_GET['type'] == 'all') {
$query_family=mysql_query("SELECT * FROM family");
}
$count=mysql_num_rows($query_family);
// result = 166
Unfortunately, the following query is wrong:
} else {
$query_family=mysql_query("
SELECT * FROM family f LEFT JOIN products p ON f.id = p.idfamily
WHERE p.type = '$_GET[type]'
");
}
$count=mysql_num_rows($query_family);
// result = 500+
it's wrong because I get all the products with a type, but I'm trying to get the number of families containing products with the selected type ($_GET[type]).
Thank you
You should have
SELECT distinct f.id from family f LEFT JOIN products p on f.id = p.idfamily WHERE p.type = '$_GET[type]' in the second query
I think.
SELECT COUNT(*) as nbr FROM family
INNER JOIN products ON products.idfamily = family.id
WHERE product.type = ".intval($_GET['type'])."
GROUP BY family.id
Avoid the mysql_ driver, use PDO or mysqli instead. Don't forget to protect you from sql injections too.
To get the count of families with a specified type, use
SELECT * FROM family f INNER JOIN products p ON f.id = p.idfamily
WHERE IFNULL(p.type, 'notspecified') = '$_GET[type]'
With INNER JOIN instead of LFET JOIN you get only rows where a connection between f.id and p.idfamily exist. By LEFT JOIN, all family rows are returned with NULL values in the fields of product table.
So when p.type is NULL, your p.type = '$_GET[type]' evaluates always to NULL, and your filtering will not work as expected. For this reason, use IFNULL.
You can try below code:
$query_family=mysql_query("
SELECT COUNT(f.id) AS cnt FROM family f
INNER JOIN products p ON f.id = p.idfamily
WHERE p.type = '$_GET[type]'");
Also try to use mysqli not mysql.
And you don't have to use mysql_num_rows, you can get the right number directly from mysql:
$query = "SELECT COUNT(DISTINCT f.id) ".
"FROM family f ".
"LEFT JOIN products p ON f.id = p.idfamily ".
"WHERE p.type = '".$_GET['type']."'";
Use INNER JOIN instead of LEFT.

How does one craft an array from LEFT JOINs when joined tables have multiple matches and GROUP BY omits needed rows

I was presented with something PHP/MYSQL related today that I was unsure exactly how to approach.
I am running this query against an altered vbulletin database:
SELECT
p.postid,
p.threadid,
p.parentid,
p.username,
p.title,
p.dateline,
p.pagetext,
p.allowsmilie,
p.visible,
pe.post_type,
pe.element_type,
pe.element,
pr.region_id,
th.threadid,
th.title,
th.forumid,
th.lastpost,
th.lastposter,
th.lastpostid,
th.similar,
at.contentid,
at.attachmentid,
p.attach
FROM thread AS th
JOIN post as p ON p.threadid = th.threadid
LEFT JOIN post_element AS pe ON pe.post_id = p.postid
LEFT JOIN post_region AS pr ON pr.post_id = p.postid
LEFT JOIN attachment AS at ON at.contentid = p.postid
GROUP BY p.postid;
The issue with the above is that sometimes there is 2, 3, or 4 rows from post_element that have the same post_id == p.postid. In that case the GROUP BY returns the 1st match and omits the 2nd 3rd....etc....
What I really desire is to create an array in something like:
while ($row = mysql_fetch_assoc($result)) {
}
that builds nested arrays for the pe.element, pe.post_type, pe.element_type fields when there is more than one match on post_id.
I was able to hack this by using this:
SELECT
p.postid,
p.threadid,
p.parentid,
p.username,
p.title,
p.dateline,
p.pagetext,
p.allowsmilie,
p.visible,
group_concat(pe.post_type) as post_type,
group_concat(pe.element_type) as element_type,
group_concat(pe.element) as element,
group_concat(pr.region_id) as region_id,
th.threadid,
th.title,
th.forumid,
th.lastpost,
th.lastposter,
th.lastpostid,
th.similar,
at.contentid,
at.attachmentid,
p.attach
FROM thread AS th
JOIN post as p ON p.threadid = th.threadid
LEFT JOIN post_element AS pe ON pe.post_id = p.postid
LEFT JOIN post_region AS pr ON pr.post_id = p.postid
LEFT JOIN attachment AS at ON at.contentid = p.postid
GROUP BY p.postid'
and then
$row['element'] = explode(",", $row['element']);
inside of the aforementioned mysql_fetch_assoc while loop...
but how would you craft an array with PHP that has only one $row for each post_id == postid with a nested array for fields that have multiple matches from $result?
Many Many thanks for your brainPower!
I would select the first as you are currently, add a count(pe.post_id) to the query and if that number is greater than 1, theuy just query that table directly
If > 50% have more than 1 then always use the second query and never check for it.
so
//do main query
foreach($post as &$p) {
$elements = array();
$p['elements'] = getElements($p['postid'])
}

how to remove duplicated columns and group column

Hello guys i currently have a MySQL query that works perfectly fine, but the only thing i don't like is that when I get returned data, some rows come duplicated except for the last column of the row .
I guess the reason why is because when I'm selecting everything including the left join, the commenttext column contains the data for a post submitted by a user.
For example) If I post a post with id of 1 and 5 people comment on that post MySQL query will bring up 5 rows with all the data in every column the same except for the last column containing the different comment pertaining to the post.
So far here is my MySQL query. How can I make it where it doesn't bring back duplicated data but only the comments grouped with the id of the post or how can i store all the comments to an array so when I run a foreach loop I can then run the comments array inside with a while loop. The reason I would use a foreach loop is to export the data with html .
SELECT
b.id
, b.from_user
, b.dateadded
, b.posttype
, b.posttext
, b.photoname
, b.blahchoice
, b.commentschoice
, b.mood
, c.defaultphoto
, d.firstn
, d.lastn
, e.status
, f.topostid
, f.commenttext
FROM
t_board b
INNER JOIN
t_userprofiles c ON b.from_user = c.user_id
INNER JOIN
t_users d ON b.from_user = d.id
INNER JOIN
t_friendship e ON e.friend_ids = b.from_user
LEFT JOIN
t_postcomments f ON f.topostid = b.id
WHERE
e.status = 'Friend'
AND e.user_ids = :id
ORDER BY
b.id DESC
One way to do it is group_concat() the comments and while you run inside the loop explode() the comments and then do foreach to display the the comments under the id
SELECT b.id,
b.from_user,
b.dateadded,
b.posttype,
b.posttext,
b.photoname,
b.blahchoice,
b.commentschoice,
b.mood,
c.defaultphoto,
d.firstn,
d.lastn,
e.status,
f.topostid,
group_concat(f.commenttext) as commenttext
FROM t_board b
INNER JOIN t_userprofiles c ON b.from_user = c.user_id
INNER JOIN t_users d ON b.from_user = d.id
INNER JOIN t_friendship e ON e.friend_ids = b.from_user
LEFT JOIN t_postcomments f ON f.topostid = b.id
WHERE e.status = 'Friend'
AND e.user_ids = :id
group by b.id
ORDER BY b.id DESC
NOTE that while you execute the query on PHP commenttext will all be comma separated and inside the loop to fetch the data for each b.id you will have all the comments for that id as comma - separated string , you can explode it to generate another array and display them.
Also some of your comments may have comma in it so you may need to provide a separator for group_concat something as below or can choose any custom operator.
group_concat(f.commenttext SEPARATOR '||' ) as commenttext
AND explode the data with ||
NOTE : The result is truncated to the maximum length that is given by
the group_concat_max_len system variable, which has a default value of
1024
http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
Combine the entries for the same post in your PHP fetch loop:
$results = array();
while ($row = $stmt->fetch()) {
if (isset($results[$id]) {
$results[$id]['comments'][] = $row['commenttext'];
} else {
$row[$id] = $row;
$row['comments'] = array($row['commenttext']);
}
}

How to fetch the linked names?

I have fetched the data from two different tables is this.
But now, I want the following result with their original names and not the numbers like status 1 is for Good, and user_id=1 means "Mike".
To select usernames using userID try using an inner join
And/or you can say 1 = good like so:
if($status == 1)
{
echo "Good";
}
(though this can also be done with the inner join, if you have the values in another table ofcourse)
Just JOIN your tables, something like:
SELECT f.FollowDate, s.StatusName, u.UserName
FROM Folowers f
INNER JOIN Users u ON f.UserId = u.ID
INNER JOIN Statuses s ON f.StatusID = s.ID

Categories