SQL displaying multiple records - php

I am currently working on a school time-table management system wherein the student dashboard, Time-table is displayed according to the current day, but when displaying the data, two duplicates come out of nowhere.
Initially, I joined the tables 'students' and 'timetable' through an 'INNER JOIN', but the problem with it was duplicates being placed simultaneously which was later fixed with 'RIGHT JOIN'.
Now, the duplicates display after the entire table has been printed.
HERE IS THE CODE BELOW:-
<?php
require_once("connection.php");
function information($subject, $time, $day, $teacher){
$element = "
<tr>
<td>$subject</td>
<td>$time</td>
<td>$day</td>
<td>$teacher</td>
</tr>
";
echo $element;
}
function getData(){
global $conn;
$sql = '
SELECT DISTINCT students.roll_no
, students.class_room
, timetable.subject_name
, timetable.time_code
, timetable.day_otw
, timetable.teacher_name
FROM students
RIGHT
JOIN timetable
ON students.class_room = timetable.room_no;
';
$result = mysqli_query($conn, $sql);
$mydate=getdate(date("U"));
if(mysqli_num_rows($result) > 0){
while($row=mysqli_fetch_assoc($result)){
if($mydate['weekday'] == $row['day_otw']){
information($row['subject_name'], $row['time_code'], $row['day_otw'], $row['teacher_name']);
}
}
} else {
echo "
<h1 class=\"check-data\">Sorry, You haven't been assigned a class yet!</h1>
<h3 class=\"ask\">Please contact your teacher/supervisor for more information.</h3>
";
}
}
getData();
?>
SO BASICALLY THE ENTIRE TABLE IS BEING DUPLICATED TWICE.

Outer joining makes no sense here. You neither want students without a timetable entry (LEFT OUTER JOIN), nor timetable entries without students (RIGHT OUTER JOIN). Then you are using DISTINCT because you are fightig duplicates, which is a bad idea, because thus you don't examine where the duplicates stem from. There should be no duplicates in the first place, so probably there is something wrong with the join criteria or data. You should fix this instead of looking for inappropriate workarounds.
Your join criteria is that the student is in the same room as the timetable entry. Why is the student associated a room? Do all the student's classes take place in the same room? In that case, yes, a class room would mean a class and then the tables would be related by the class (room). But if that were the case, you would get no duplicates.
I assume there to be something else to relate students with the timetable. Look for a student ID in the timetable. Something like:
SELECT s.roll_no, s.class_room, t.subject_name, t.time_code, t.day_otw, t.teacher_name
FROM students s
JOIN timetable t ON s.student_id = t.student_id
ORDER BY s.student_id, t.day_otw, t.time_code;
Or maybe there is something like an additional class ID, both student and timetable belong to? (The room in both tables would look strange then, however.) Maybe you don't know the database well enough. If this is the case, ask somebody who does.

From your screen, you only need to display timetable data, so there is no point to link to student table
Please consider using the following instead of your right join
SELECT
timetable.subject_name, timetable.time_code,
timetable.day_otw, timetable.teacher_name
FROM timetable

Related

join issue MYSQL/PHP

i have a bit of a problem, ive never used JOIN before, and this is the first time, and i got into some problems:
<?php
//$count to keep the counter go from 0 to new value
$count=0;
//I need to select the level for the users building first, meanwhile i also
//need to get the money_gain from the table buildings, which is a table that
//is common for each member, which means it doesnt have a userid as the other table!
//And then for each of the buildings there will be a $counting
$qu1 = mysql_query("SELECT building_user.level,buildings.money_gain FROM building_user,buildings WHERE building_user.userid=$user");
while($row = mysql_fetch_assoc($qu1))
{
$count=$count+$row['level'];
echo $row['level'];
}
?>
So basically ive heard that u should tie them together with a common column but, in this case thir isnt any.. im just lost right now?
EDIT Oh right, I need the right level to be taken out with the correct money_gain too, in building_user its 'buildingid'and in buildings, its just 'id'! have no idea how to make a common statement though!
From your edit,
SELECT building_user.level,buildings.money_gain FROM building_user,buildings WHERE building_user.userid=$user AND building_user.buildingid = building.id;
You essentially get the records for the user joining them at the building id
Performance-wise, joins are a better choice but for lightweight queries such as this, the query above should work fine.
You can also give each column a neater name
SELECT building_user.level as level,buildings.money_gain as money gain FROM building_user,buildings WHERE building_user.userid=$user AND building_user.buildingid = building.id;
and access them as
$level = $row['level'];
$gain = $row['gain'];
i think you problem is, that MySQL doesn't know how to JOIN the two Tables. Therefor you have to tell MySQL how to do that.
Example
SELECT * FROM TABLE1 INNER JOIN Table1.col1 ON TABLE2.col2;
where col1 and col2 are the columns to join (a unique identifier)
<?php
$count=0;
$qu1 = mysql_query("SELECT bu.level, bs.money_gain FROM building_user bu, buildings bs WHERE bu.userid=$user");
while($row = mysql_fetch_assoc($qu1))
{
$count=$count+$row['level'];
echo $row['level'];
}
?>
Try this
$qu1 = mysql_query("SELECT building_user.level,buildings.money_gain
FROM building_user
JOIN buildings ON building_user.building_id = buildings.id
WHERE building_user.userid=$user");
building_user.building_id is the foreght key of table building_user and
buildings.id is the primary key of table buildings

Joining multiple tables using PHP relating to a member id

I'm really hoping that you can clear things up for me regarding JOIN using php as I'm really struggling to come to terms with how it works.
Basically I have 2 tables, one for premium members and another for fans of these members. So I want to get certain information from the "premium" table where a member ($memberid) is a fan.
Premium = id, name, avatar, town, etc, etc
Fans = fan($memberid), fanee(Premium ID)
So I have this code at the moment:
<?php
$get_connections_sql = "SELECT id, name, avatar, town FROM premium LEFT JOIN fans ON fans.fanee=premium.id WHERE fans.fan=$memberid LIMIT 18";
$get_connections_res = mysqli_query($con, $get_connections_sql);
if(mysqli_affected_rows($con)>0){
while ($connections = mysqli_fetch_assoc($get_connections_res)){
$connectionid = $connections['id'];
$connectionname = $connections['name'];
$connectiontown = $connections['town'];
$connectionavatar = $connections['avatar'];
$connections .= "
<div class=\"connectionHolder\"><img class=\"connection\" src=\"uploads/avatars/pro/$connectionavatar\" /></div>
";
}
}else{
$connections = "
<div class=\"noContent\">There are no connections to be shown</div>
";
}
?>
This is returning the else condition so there must be something wrong with my JOIN row - Can anyone please point me in the right direction.
You've said that the column 'id' is ambiguous, this is because you have two tables referenced in your query both with 'id' columns and MySQL does not know which to choose. You can be specific by adding the table name like this:
SELECT premium.id, ...
Additionally, you'll want mysqli_num_rows() instead of mysqli_affected_rows(). Since your query does not affect any rows (like update, delete, insert), instead it's returning a set of rows.
mysql_num_rows() takes the result of a query as its parameter (in your case $get_connections_res) rather than the connection. To make sure that the result is valid first check the value of $get_connections_res before the if... if it's falsey then there's an error in the query. Use mysqli_error() to report the error.

SQL query ORDER BY looping in PHP

EDIT: Added the first SQL query.
A section of my website has two dropdown menus. All the options in both are populated using SQL queries. Dropdown#1 is a list of class sections (like A1 for example). Once the professor selects a section, Dropdown#2 is populated with the student ID's (like 1234567 for example).
Student information is found in table 1. Among this information is the 'professorName' column. In order to associate the student with a class section, I need to match 'professorName' column with an identical column found in table 2, because class sections are only found in table 2.
Till here everything works great, because at the end of my query I put ORDER BY student ID. However, two of the class sections are associated to two different professors. In order to deal with this issue, I used the following code to loop through each professor name.
$from site = $_POST['section'];
$query = ("SELECT professorName FROM Table 2 WHERE classSection='$fromsite'");
$NumberofProfessorNames = $objMSSQL->getAffectedRows();
echo $NumberofProfessorNames;
for ($j=0; $j<$NumberofProfessorNames; $j++)
{
$section= $query[$j][professorName];
$output = $objMSSQL->getTable("SELECT DISTINCT StudentID from table1 WHERE professorName='$section' ORDER BY StudentID");
for ($i=0; $i<$objMSSQL->getAffectedRows(); $i++)
{
echo "<option value='".$output[$i][studentID]."'>".$output[$i][studentID]."</option>";
}
}
The problem is that for the only two sections where this is even necessary (because there are two professorNames), since it is looping like this, it is ending up ordered like this in the dropdown#2:
1234567
2345678
3456789
4567890
1234123
2345765
3456999
4567000
My limited experience in programming is keeping me from understanding how I can fix this seemingly simple issue.
Thank you for your help.
Rather than loop over the professors and query table1 for each, join table1 and table2 in the second query and only query the database once. For example:
$query = [... FROM Table2...];
$NumberofProfessorNames = $objMSSQL->getAffectedRows();
echo $NumberofProfessorNames;
$output = $objMSSQL->getTable("
SELECT DISTINCT StudentID
from table1
join table2
on ...
WHERE [the same clause you used in $query]
ORDER BY StudentID"
);
for ($i=0; $i<$objMSSQL->getAffectedRows(); $i++)
{
echo "<option value='".$output[$i][studentID]."'>".$output[$i][studentID]."</option>";
}
It's more elegant (and almost certainly more efficient) than generating a WHERE IN clause.
Yu can do it this way:
$section = "('";
for ($j=0; $j<$NumberofProfessorNames; $j++)
{
$section.= $query[$j][professorName] . "','";
}
$section = substr($section, 0, -3) . ')'; //$section contains ('prof1','prof2')
$output = $objMSSQL->getTable("SELECT DISTINCT StudentID from table1 WHERE professorName IN $section ORDER BY StudentID");
for ($i=0; $i<$objMSSQL->getAffectedRows(); $i++)
{
echo "<option value='".$output[$i][studentID]."'>".$output[$i][studentID]."</option>";
}
that is querying for all your professors in just one sql with IN() syntax.
UPDATE: I've just noted you use sql server instead of mysql, so I've changed the IN() syntax a bit and change the link to the sql server help docs.
It sounds like your tables aren't normalized. Good form would have a sections table, a students table, and a professors table. Information in each table should be specific to the table's topic.
students
student_id
student_last_name
student_first_name
student_address
etc
sections
section_id
section_name - multiple sections can tend to have the same name but differing content
section_description
section_year - sections can change from year to year
faculty
faculty_id
faculty_name - this is not a key field, more than one person can have the same name.
faculty_address
faculty_type - adjunct, fulltime, etc.
You would then have relational tables so you can associate professors with sections and students with sections.
faculty_2_sections
f2s_id
faculty_id
section_id
student_2_sections
s2s_id
student_id
section_id
This makes it super simple because if a student is logged in, then you already have their student id. If it's a professor, you already have their faculty_id
If you're pulling for students, your sql might look like this:
$sql = "select * from students s,sections sc,faculty f,faculty_2_sections f2s,student_2_sections s2s where student_id='$student_id' and s2s.student_id=s.student_id and s2s.section_id=sc.section_id and f2s.faculty_id=f.faculty_id and f2s.section_id=s2s.section_id";
If you're pulling for faculty you would do this:
$sql = "select * from students s,sections sc,faculty f,faculty_2_sections f2s,student_2_sections s2s where faculty_id='$faculty_id' and f2s.faculty_id=f.faculty_id and f2s.section_id=s2s.section_id and s2s.section_id=sc.section_id and s2s.student_id=s.student_id";
You can then pull a list of sections to populate the section_ids pull-down to only show students or faculty for a specific section.

List rows in table with date information

I am in the beginning of building a simple absence script for teachers to administrate students.
I need to populate the same list of students in 5 tables. One table for each day of the current week (monday to friday).
I have the following code at the moment
List students SQL query:
SELECT s.student_id, s.student_firstname, s.student_lastname,
a.student_absence_startdate, a.student_absence_enddate, a.student_absence_type
FROM students s
LEFT JOIN studentabsence a ON a.student_id = s.student_id
WHERE a.student_absence_startdate
IS NULL OR
'2012-06-20'
BETWEEN
a.student_absence_startdate AND a.student_absence_enddate
This query selects all students and joins another table wich is a linking table that holds the absence information for students.
I the populate the code 5 times like this:
<?php
$data = array();
while ($row = mysql_fetch_array($list_students)) {
$data[] = $row;
}
?>
<table>
<?php
foreach($data as $row){
$class = "";
if ($row['student_absence_type'] == 2) {$class = " style='background:#f00;'";}
else if ($row['student_absence_type'] == 3) {$class = " style='background:#8A2BE2;'";}
echo "<tr><td$class>";
echo "<a class='ajaxlink' href='#' rel='pages/ajaxAbsence.php?student_id=".$row['student_id']."'>".$row['student_firstname']." ".$row['student_lastname']."</a>";
echo "</td></tr>\n";
}
?>
</table> <!-- Repeat -->
My question is how I should manage the date functions.
As you can see in my SQL query I have hardcoded the dates. I need it to automatically select the date of wich table the students are listed.
for example:
table > Monday (2012-07-23)
the user John Doe has absence information in this span, based on the above query. Let's change the background of <td>
table > Tuesday (2012-07-24)
the user John Doe has no absence information in this span. Just list him.
etc...
I am not expecting you to write my code. I am just curious on how to think. I am fairly new to programming.
The most flagrant error I find in your thoughts is that you don't need those five tables. You'll end up repeating and messing data.
You need different tables, from what I've read.
Students
ID, Name, etc..
Classes
class_id, name,
Teachers
Id_teacher, name, etc
TeachersInClass (so you can now which teachers gave a specific class)
id, id_teacher, id_class
Absences
id, id_student, id_class, date
This leaves you a more robust database, and you can play arroud with multiple associations like, which teachers had the most absences in a year... etc etc.
EDIT: Forgot to answer your "real" question.
You can use the PHP DateTime class to manipulate your dates. It's easy to use, and the php.net has a lot of good examples to give you a boost start

What's the most efficient way to pull the data from mysql so that it is formatted as follows:

I have a table that has patient information (name, dob, ssn, etc.) and a table that has lists of medications that they take. (aspirin, claritin, etc.) The tables are related by a unique id from the patient table. So, it's easy enough to pull all of Mary Smith's medications.
But, what I need to do is to show a paginated list of patients that shows their name, other stuff from the patient table and has a column with a line-separated list of their medications. Roughly, this:
If I do a simple left join, I get 3 repeated rows of Mary Smith with one medication per row.
The patient table can have thousands of records, so I don't want to do a query to get all the patients and then loop through and get their meds. And, because it's paginated based on patient, I can't figure out how to get the correct number of patients for the page, along with all their medications.
(The patients/medications thing is just a rough example of the data; so please don't suggest restructuring how the data is stored.)
GROUP_CONCAT to the rescue!
SELECT patients.first_name, patients.last_name, GROUP_CONCAT(prescriptions.medication SEPARATOR ", ") AS meds FROM patients LEFT JOIN prescriptions ON prescriptions.patient_id = patients.id GROUP BY patients.id;
You've got a few choices.
rowspan clauses with one drug per cell per user. You'd need to run two SQL queries to precalculate how big each user's span would have to be, or suck the query results into PHP and do the counting there.
Simple state machine - start a new row each time the user changes, then just keep adding more drug names seperated with <br /> while the user's name stays constant.
The second one's probably easiest:
$previous_name = null;
$first = true;
echo "<table";
while($row = mysql_fetch_assoc($results)) {
if ($row['name'] <> $previous_name) {
if (!$first) {
echo "</td></tr>"; // end previous row, if it's not the first row we've output
$first = false;
}
echo "<tr><td>$row[name]</td><td>"
$previous_name = $row['name'];
}
echo "$row['drug']<br />";
}
echo "</td></tr></table>";
I think what you are looking for is referred to a 'concation of subquery'.
Check http://forums.mysql.com/read.php?20,157425,157796#msg-157796 and http://mysql.bigresource.com/SELECT-CONCAT-Subquery-S5cIpzqO.html

Categories