I have data coming from the database , i am using JOIN(s) to select data from different tables,I need to be able to group the data together based on the specific id of the user in relation to the specific course, as an email needs to be sent based on the selection and within this selection(using a radio button) it will allow admin to be able to email all the users assigned to that specific category selected
i am currently getting duplicated data, like the users details will show on each category instead of being in one single category to pass into the array to email. I only need to select one radio button per category/course but now i am getting multiple radio buttons.
here is my query:
$query="SELECT * FROM course_student
JOIN course ON course.course_id=course_student.course_id
JOIN student ON student.student_id=course_student.student_id
WHERE course.course_id=course_student.course_id
ORDER BY course.course_id";
this is my loop to select data -- it's creating duplicate names for the entries where i just want one name with all of the data that is supposed to be in it
$result=mysqli_query($connection,$query);
confirmation($connection);
while($course_email_students = mysqli_fetch_assoc($result)){
$course_email = $course_email_students['student_email'];
$course_name = $course_email_students['course_name'] ."<br/>";
here is my html:
<input type="radio" name="course_mail[]" value="<?php echo $course_email ;?>">
<?php echo $course_name ?>
<?php } ?>
here is more code
html
<form action ="#" method="POST">
<P> <label for="">Send to specific student courses</label>
</p>
<?php // email specific students
$query = "SELECT student.student_email, course.course_name, course.course_id
FROM course_student
JOIN student ON student.student_id=course_student.student_id
JOIN course ON course.course_id=course_student.course_id
GROUP BY student.student_email, course.course_id
ORDER BY course.course_id";
$result=mysqli_query($connection,$query);
confirm_query($connection);
while($course_email_students=mysqli_fetch_assoc($result)){
$course_student_email=$course_email_students['student_email'];
$course_student_email_name=$course_email_students['course_name'] ."<br/>";
var_dump($course_email_students['student_email']);
?>
<input type="radio" name="course_email[]" value="<?php echo $course_student_email ;?>">
<?php echo $course_student_email_name ?>
<P> <label for="">Message</label>
<p><textarea rows="10" cols="20" name="message"></textarea></p>
</p>
<input type="submit" name="submit" value="send">
here is the php for testing to see what comes through
if(isset($_POST['submit'])){
// do validation
if(isset($_POST['course_email'])){
var_dump($_POST['course_email']);
}
}
From the PHP you've posted, it appears that you are just using data from two, possibly three columns in your query. If so, it is much more efficient to select the specific columns you're interested in in the SQL. There's also a redundancy in the query where you're using the same condition for a WHERE as you have in a JOIN:
$query="SELECT student.student_email, course.course_name, course.course_id FROM course_student
JOIN student ON student.student_id=course_student.student_id
JOIN course ON course.course_id=course_student.course_id <-- !!!
WHERE course.course_id=course_student.course_id <-- !!!
ORDER BY course.course_id";
There are two ways of selecting unique combinations of results with this select query; you can use DISTINCT or GROUP BY.
DISTINCT:
$query = "SELECT DISTINCT student.student_email, course.course_name, course.course_id
FROM course_student
JOIN student ON student.student_id=course_student.student_id
JOIN course ON course.course_id=course_student.course_id
ORDER BY course.course_name";
GROUP BY:
$query = "SELECT student.student_email, course.course_name, course.course_id, student.student_id
FROM course_student
JOIN student ON student.student_id=course_student.student_id
JOIN course ON course.course_id=course_student.course_id
GROUP BY student.student_email, course.course_name
ORDER BY course.course_name";
Now for the PHP code:
$c_name = ''; # course name
$c_id = ''; # course ID
$students = array();
while($aa = mysqli_fetch_assoc($result){
if ($aa['course_name'] !== $c_name) {
# the course name has changed. print out the course and student data
make_radios($c_name, $c_id, $students);
# set c_name to the new course name
$c_name = $aa['course.course_name'];
$c_id = $aa['course.course_id'];
# set the students to the new student
$students = array( $aa['student.student_email'] );
}
else {
# add this student to the list of students
$students[] = $aa['student.student_email'];
}
}
# print out the last set of data
make_radios( $c_name, $c_id, $students );
function make_radios( $course_name, $course_id, $email_arr ) {
$html = '<input type="radio" id="email'
. $course_id . '" name="course_email[]" value="'
. implode(',', $email_arr) . '"> <label for="email'
. $course_id . '">$course_name</label>';
# I don't know if you want to list all the email addresses or not... in case you do:
$html .= "<ul>";
foreach ($email_arr as $e) {
$html .= "<li>$e</li>\n";
}
$html .= "</ul>";
# append the message box
$html .= '<label for="message' . $course_id . '">Message</label>'
. '<textarea id="message' . $course_id . '" rows="10" cols="20" name="message">'
. "</textarea>\n";
echo $html; # or you could return $html
}
I would not recommend that you have the email addresses on the form--I'd use the student IDs and the students' names instead, and then have your script pull the appropriate email addresses from the database--but it's up to you, obviously.
Please read through the code and check you understand what it's doing. I'm happy to answer any questions.
Group and Order are words that have meaning both in English and in SQL jargon. You've said you want your values grouped. I think you mean, in SQL terms, you want them ordered, in such a way that each course's student emails are together.
There are some problems with your query.
First, Pro tip: Avoid using SELECT * in software. (It's OK when you're troubleshooting databases, but it's wasteful and confusing in software, especially when you're JOINing more than one table.)
Second, you have this condition repeated in both your JOIN...ON and your WHERE clause. That's redundant.
course.course_id = course_student.course_id
Leave it in your ON clause and out of your WHERE clause.
Third, your result set's order is underdetermined. This may not matter, but you are ordering only by course id. If you care whether your result set is ordered by student email, then mention it in the ORDER BY clause.
Fourth, you do have three tables. But one of them, course_student, appears to be a classic join table allowing there to be a many-to-many relationship between courses and students. So it seems likely you only have two tables with actual application data items in them.
Finally, from the code in your question it looks like you want
course_id
course_name
student_email
in your result set generated by your SELECT query. Your question's narrative mentions category, but because you've used SELECT * we can't tell what you mean by that.
To get the unique values of those three fields in your result set, use this query:
SELECT DISTINCT
course.course_id,
course.course_name,
student.student_email
FROM course_student
JOIN course ON course.course_id=course_student.course_id
JOIN student ON student.student_id=course_student.student_id
ORDER BY course.course_id, student.student_email
The DISTINCT qualifier eliminates duplicates.
From your comment, it's still hard to tell what you want. But it seems that you want to try this:
SELECT GROUP_CONCAT(DISTINCT course.course_name),
student.student_email
FROM course_student
JOIN course ON course.course_id=course_student.course_id
JOIN student ON student.student_id=course_student.student_id
GROUP BY student.student_email
ORDER BY student.student_email
Or maybe you want this.
SELECT GROUP_CONCAT(DISTINCT student.student_email),
course.course_name
FROM course_student
JOIN course ON course.course_id=course_student.course_id
JOIN student ON student.student_id=course_student.student_id
GROUP BY course.course_name
ORDER BY course.course_name
This second one is going to fail in your large courses because of a limitation of GROUP_CONCAT(). You may need to write application code to organize your web page course by course, or student by student.
Related
I connected, I created a quick script in which I want to manage clients, domains and notes.
The problem is that when I add 2 notes to the client from ID: 1 - after viewing I see only one.
The following code shows what I have done so far
SQL Query:
$sql = "SELECT * FROM domain JOIN note ON domain.id = note.domain_id GROUP BY domain.id";
My PHP code:
while($rs = $resultdb->fetch_array(MYSQLI_ASSOC)) {
echo '<tr>';
echo '<td>'.$rs["id"].'</td>';
echo '<td><strong>'.$rs["domain_name"].'</strong></td>';
echo '<td>'.$rs["note"].'</td>';
echo '</tr>';
}
The result he gets is:
ID DOMAIN NOTE
1 "domain1.com" "note 1 to domain1.com"
2 "domain2.com" "note 2 to domain2.com"
However, in the database I have added a few notes to domain1.com.
I would like to see all the notes added to a given domain.
EDIT:
When I do: "SELECT * FROM domain JOIN note ON domain.id = note.domain_id";
I getting:
I getting
I expect
EDIT: Add screnshot
LEFT JOIN
Your GROUP BY is limiting the records retrieved by the query. If you want all of the notes together you can try using GROUP_CONCAT() to produce a single field with all of the notes in one...
$sql = "SELECT domain.id as id, domain.domain_name as domain_name,
GROUP_CONCAT(note.note) as note
FROM domain
LEFT JOIN note ON domain.id = note.domain_id
GROUP BY domain.id";
You might also change the JOIN to LEFT JOIN in case there are no notes for a particular domain.
Probably you need to use a separate query to get "Domain Notes" in the while. for example:
while ($rs = $resultdb->fetch_array(MYSQLI_ASSOC)) {
$sql_notes = "SELECT * FROM notes WHERE domain_id = '" . (int)$rs['domain_id'] . "'";
...
}
you need group_concat group by note.domain_id
if you need exact match the use inner join
"SELECT id, domain, group_concat(note) as note
FROM domain
INNER JOIN note ON domain.id = note.domain_id
GROUP BY note.domain_id";
if you needc result also for id without notes then try
"SELECT id, domain, (group_concat(ifnull(note,'')) as note
FROM domain
LEFT JOIN note ON domain.id = note.domain_id
GROUP BY note.domain_id";
I'm working on a system, and this module is supposed to echo the contents of the database.
It worked perfectly until I added some JOIN statements to it.
I've checked and tested the SQL code, and it works perfectly. What's not working is that part where I echo the content of the JOINed table.
My code looks like this:
$query = "SELECT reg_students.*, courses.*
FROM reg_students
JOIN courses ON reg_students.course_id = courses.course_id
WHERE reg_students.user_id = '".$user_id."'";
$result = mysqli_query($conn, $query);
if (mysqli_fetch_array($result) > 0) {
while ($row = mysqli_fetch_array($result)) {
echo $row["course_name"];
echo $row["course_id"];
The course_name and course_id neither echo nor give any error messages.
UPDATE: I actually need to increase the query complexity by JOINing more tables and changing the selected columns. I need to JOIN these tables:
tutors which has columns: tutor_id, t_fname, t_othernames, email, phone number
faculty which has columns: faculty_id, faculty_name, faculty_code
courses which has columns: course_id, course_code, course_name, tutor_id, faculty_id
I want to JOIN these tables to the reg_students table in my original query so that I can filter by $user_id and I want to display: course_name, t_fname, t_othernames, email, faculty_name
I can't imagine that the user_info table is of any benefit to JOIN in, so I'm removing it as a reasonable guess. I am also assuming that your desired columns are all coming from the courses table, so I am nominating the table name with the column names in the SELECT.
For reader clarity, I like to use INNER JOIN instead of JOIN. (they are the same beast)
Casting $user_id as an integer is just a best practices that I am throwing in, just in case that variable is being fed by user-supplied/untrusted input.
You count the number of rows in the result set with mysqli_num_rows().
If you only want to access the result set data using the associative keys, generate a result set with mysqli_fetch_assoc().
When writing a query with JOINs it is often helpful to declare aliases for each table. This largely reduces code bloat and reader-strain.
Untested Code:
$query = "SELECT c.course_name, t.t_fname, t.t_othernames, t.email, f.faculty_name
FROM reg_students r
INNER JOIN courses c ON r.course_id = c.course_id
INNER JOIN faculty f ON c.faculty_id = f.faculty_id
INNER JOIN tutors t ON c.tutor_id = t.tutor_id
WHERE r.user_id = " . (int)$user_id;
if (!$result = mysqli_query($conn, $query)) {
echo "Syntax Error";
} elseif (!mysqli_num_rows($result)) {
echo "No Qualifying Rows";
} else {
while ($row = mysqli_fetch_assoc($result)) {
echo "{$row["course_name"]}<br>";
echo "{$row["t_fname"]}<br>";
echo "{$row["t_othernames"]}<br>";
echo "{$row["email"]}<br>";
echo "{$row["faculty_name"]}<br><br>";
}
}
In my database i have created two tables , the one is "categories" and the other "click_count".
The two tables have the following information : categories( cat_id, cat_name , cat_description ) and click_count(id, cat_id, cat_count). I have already written a php code which echo a table with information about categories and i have already written a php code whick calculates the click counts, so i want a php script which i can echo on the same table the information about click_count and specify the "cat_count" which contains the number about "clicks" . The following code is obviously wrong but you can get the logic.
<?php
$sql4 = "SELECT categories.cat_id,categories.cat_name,click_count.cat_id,click_count.cat_count WHERE categories.cat_id=click_count.cat_id";
$result4 = mysqli_query($conn, $sql4);
$row4 = mysqli_fetch_array($result4);
while($row4 = mysqli_fetch_assoc($result4)) {
echo '<td>'.$row4['cat_count']; }?>
The SELECT statement should contain a JOIN:
SELECT categories.cat_id, categories.cat_name, click_count.cat_id, click_count.cat_count
FROM categories
LEFT JOIN click_count
ON categories.cat_id = click_count.cat_id;
...and you can also add a WHERE clause at the end if you need it to select not all, but only the ones that fit a certain condition.
I've searched and found ways to do queries inside queries, but I have not found the right answer.
What I am trying to do is to fetch comments from the table called users_profiles_comments and by doing that I will get the field of '.$member["author"].'. Then I want to show who made the comment with their rank and a display picture.
But because there is no user details stored in the comments table because its for comments, I need to create a query inside of my query result where I can have this:
"SELECT * FROM users WHERE username = $member['author'] ORDER BY `id` ASC"
The '.$member["author"].' value comes from the main query but I need it so it can find fields in my users table.
$sql = "SELECT * FROM users_profiles_comments WHERE postid = '1' ORDER BY `id` ASC";
$stm = $dbh->prepare($sql);
$stm->execute();
$users = $stm->fetchAll();
foreach ($users as $row) {
print '
<img src="'.$member["profilepic"].'" style="float:left;margin-right:10px;" width="80px" height="85pxm">
<h4>'. $row["author"] .'
<small>'. $row["date"] .'</small>
</h4>
<p>'. $row["content"] .'</p><hr> </a></li>';
}
echo '
</div>
';
I hope you understand.
Edit:
The database.
users Table
http://img855.imageshack.us/img855/4387/qyjl.png
users_profiles_comments table
http://i.imgur.com/aKRF5MN.png
But because there is no user details stored in the comments table because its for comments
This is good. You do not want to have your database information duplicated in both tables (de-normalized data) - there is no need.
Generally a foreign key is added to inverse side of the relationship. This would mean you have a user_id column within your comments table, allowing you to select the data in one query using a JOIN
SELECT comment.*, user.name AS comment_author
FROM comment
INNER JOIN user ON user.id = comment.user_id
WHERE user.id = 123
Edit - I flipped to JOIN to return comments rather than users, (as you said "to fetch comments") however both ways will work, it just depends which side of the relationship you are on.
Edit 2 To respond to your comment;
How would I be able to show this on my PHP code on the result?
you can be more specific with the above query (not use *) and render it as follows :
$sql = "
SELECT
comment.`date` as comment_date,
comment.content,
user.name AS author_name,
user.profilepic as author_pic
FROM
users_profiles_comments as comment
INNER JOIN
user ON user.id = comment.user_id
WHERE
comment.postid = 1
";
//...
$comments = $stmt->fetchAll();
foreach ($comments as $comment) {
echo '<img src="' . $comment['author_pic'] . '"/>';
echo '<h4>' . $comment['author_name'] . '<small>' . $comment['comment_date'] .'</small></h4>';
echo '<p>' . $comment['content'] . '</p>';
}
You can select member name in SQL statement. You can try this query, this query will bring all the information from two table if users.username = users_profiles_comments.author
WAY 1:
SELECT t1.*, t2.* FROM
(
SELECT * FROM users WHERE username = '.$member["author"].' ORDER BY `id` ASC
) AS t1
LEFT JOIN
(
SELECT * FROM users_profiles_comments WHERE postid = '1' ORDER BY `id` ASC
) AS t2
ON t1.username = t2.author
Finally, do your foreach to print
===================================================================
WAY 2:
You can try this also-
SELECT *,
(SELECT profilepic FROM users WHERE users.username = users_profiles_comments.author) AS profilepic
FROM users_profiles_comments WHERE postid = '1' ORDER BY `id` ASC
And print profilepic using $row['profilepic'] in your foreach loop
=====================================================================
WAY 3:
SELECT t1.*, t2.* FROM
(
SELECT * FROM comments WHERE postid = '1'
) AS t1
LEFT JOIN
(
SELECT * FROM users
) AS t2
ON t1.author = t2.username
What I understand is that you need to get information about the user from another table called user_profile_comments, based on the user id (correct me if wrong: :-)). Use a left outer JOIN to fetch data from another table, limited on user id.
See http://www.w3schools.com/sql/sql_join.asp for more info.
I have quite a bit of knowledge about SQL queries.
I'm trying to make gallery, and I need to select categories from table "cat_photos", which contain rows (id,name,cover,photo) and count number of photos from table "photos" which contain rows (id,thumb,photo,category).
Here is code which i use:
1) Selecting categories
$query = mysql_query("SELECT * FROM cat_photos ORDER BY ID DESC");
while($data = mysql_fetch_array($query)) {
echo "<li><a href='photos.php?cat=$data[id]'><img src='galleries/categories/$row[image]' alt='$row[name]' /></a>
<div class='photodesc'><div class='catname'><a href='photos.php?cat=$row[id]'>$row[name]</a></div>
<div class='catcount'>Number of photos in category</div></div></li>"; }
2) Counting number of photos in category
$query = mysql_query("SELECT category, COUNT(photo) FROM photos GROUP BY category") or die(mysql_error());
while($row = mysql_fetch_array($query)){
echo "Number of photos is ". $row['COUNT(photo)'] ." in cateogry ". $row['category'] .".";
echo "<br />"; }
Separated all works, but I can't find a way to merge them into one query.
I have googleing for "UNION", "JOIN", "LEFT JOIN" options in MySql query but I could't together the pieces.
I wonder if this is in general possible?
How in order that query look like?
Try this, it should work :
SELECT cat_photos.*, count(photos.id) as number_photos
FROM cat_photos
LEFT JOIN photos ON photos.category = cat_photos.id
GROUP BY cat_photos.id, cat_photos.name, cat_photos.image
ORDER BY cat_photos.id
The number of photos will be accessible trough $row['number_photos'].
Just use your second query and join the wanted category elements.
Something quick and dirty would be:
SELECT c.category, COALESCE(COUNT(p.photo),0) as photos FROM photos p, cat_photos c
WHERE c.category = p.category
GROUP BY category
Since I don't know your exact database setup just change the selected elements to the ones you really need.
//edit: Put in Coalesce to get categories with 0 photos.
Don't SELECT *. Instead select individual columns and then join:
SELECT
cat_photos_main.id, cat_photos_main.category, cat_photos_main.photodesc, cat_photos_counts.num_photos
FROM cat_photos cat_photos_main
LEFT OUTER JOIN (SELECT category, count(*) AS num_photos FROM photos GROUP BY category) cat_photos_counts
ON cat_photos_main.category = cat_photos_counts.category