What query would I use for this - php

I have a Relationship table that links teachers to students
Teacher Student
1 1
1 2
2 1
2 3
The Students table then has specific data about the students
Id Date of birth First Name
1 1990-10-10 Bill Smith
2 1989-01-03 Adam Smithson
I want to select all the students who are students of teacher 1. Right now i do this way (this is propel ORM syntax).
$relationships = RelationshipQuery::create()->filterByTeacher($teacherid)->find();
foreach($relationships as $relationship){
$studentId = $relationship->getStudent();
//use the studentId to get the actual student object
$student = StudentQuery::create()->findPk($studentId);
//after I get the student, I add it to an array
$students[] = $student;
}
The problem with this is that I end up with an array, and not the usual propelCollection that we end up with when we do a normal ->find(). Is there a way to clean up this query a bit (use joins or something like that) so that I end up with a PropelCollection from the start?

You should define your schema for the relationship like this: http://www.propelorm.org/wiki/Documentation/1.5/Relationships#Many-to-ManyRelationships
The code you're asking for is very easy:
$teacher = TeacherQuery::create()->findOneById($teacherId);
$students = $teacher->getStudents(); //Your students collection

Related

Many to many relationships - Moving data from many tables to a single table

I have a table with users and one with labels
A label can have many users and a user can have many labels, so a Many to Many relationship
A joining table is needed, that's why I have label_user
Below you can see pictures of what they contain with example data:
Users:
https://i.stack.imgur.com/E5E6O.png
Labels:
https://i.stack.imgur.com/1NFjq.png
label_user:
https://i.stack.imgur.com/tW2Uo.png
Let's say I have 5000 users and I can sort them by gender. Let's say 2800 of them are males, how can I assign them all to a label?
Here's some things I tried:
public function add_users_to_label($label_id, $condition, $value)
{
$db = new Database();
$conn = $db->db_connect();
$label_id = escape_string($conn, $label_id);
$query = $conn->query("INSERT INTO `label_user`(`label_id`, `user_id`) SELECT :label_id, psid FROM `iris_messenger_users` WHERE $condition = $value");
$query->bind_param("iss", $label_id, $condition, $value);
if ($query->execute()) {
return true;
}
else {
return "Error inserting data: " . $conn->error . "\n";
}
}
On the user side I have a simple form with select that let's you select a label and then this code:
if(isset($_POST['label-select'])) {
if ($_GET['show_only_gender'] == 'male') {
$condition = 'gender';
$user->add_users_to_label($_POST['label-select'], $condition, $_GET['show_only_gender']);
}
}
Basically, I want to get all users that are male and assign them to a label and put that into label_user with respectively the label_id and the user_id(psid)
Even if this worked I'd still have to do it 2699 times more. What can I do here to optimize and make it to run with 1 query if possible?
I don't think using foreach and running it as much times as there are users is the best option, is it?
Is there any better approach I can take to make this possible?
Although what you are describing does not make sense to have a "label" associated with a person for this specific component, the gender is already on the user table you should be able to get all male based on
select * from user where gender = 'male'
no need to JOIN to a label table on this field. Similarly if you were trying to find people based on a name starting with something... you would not create a label for the name either. Query directly from the table that has that specific component association.
Now, to answer your question, how to insert into the label table for each instance in bulk, you could do something like... I am doing this based on some label ID = 123 as just an example in your labels table that represents gender.
I am doing a LEFT-JOIN in the select so we dont try to add for any user IDs that are already on file do not try to get re-added.
insert into label_user
( label_id,
user_id )
select
123 as label_id,
U.id as user_id
from
users U
left join label_user LU
on U.id = LU.user_id
AND LU.label_id = 123
where
U.gender = 'male'
AND LU.user_id IS NULL
You obviously need to adjust for php.

SQL Join statement into a single field in a HTML Table using PHP

so i'm creating a schedule system and i'm trying to display the information for the appointment and also, userID's for those who have booked a possition.
I have created a table for Students, Classes and ClassAssosication where the ClassID and UserID are PK And FK from the other tables. I have created a join statement =
SELECT classes.ClassName, students.UserID
FROM classassociation
JOIN students
ON classassociation.UserID = Students.UserID
JOIN classes
ON classassociation.ClassID = classes.ClassID
WHERE classassociation.ClassID = 1;
Where it retrieves the UserID and ClassName for those who have booked a place for Class with the ID = 1 .
I am trying to create a PHP/HTML table where in a field for example, Monday 9AM, i can print out the join statement, for example, Methodology, 1 ,2 (user Id's).
Day | 9AM | 10AM
Monday | Methodology, 1,2 |
Tuesday | |
I need this done for multiple classes but trying to attempt one for now. I am unsure of how to do this, so any help will be appreciated. Thank you.
Your query as written will return a row for each ClassName/UserId pair - if there are two people in the methodology class there will be two rows in your query result.
You can choose to combine them in a loop in php, or you can alter your query to group things together. If you think of it as "I want to group all the UserIds for a given classname", it suggest how to use the GROUP BY clause in your SQL:
SELECT classes.ClassName, students.UserID
FROM classassociation
JOIN students
ON classassociation.UserID = Students.UserID
JOIN classes
ON classassociation.ClassID = classes.ClassID
WHERE classassociation.ClassID = 1
GROUP BY ClassName;
Now there will be one row for each ClassName, but you still need to tell MYSQL how to handle the multiple UserIds for each row. In your case, you want to have the UserIds joined together in a comma-separated list. Happily, there's a special section in the manual just for the functions you use with GROUP BY. In this case GROUP_CONCAT gives the desired result:
SELECT classes.ClassName, GROUP_CONCAT(students.UserID SEPARATOR ',') AS UersIds
FROM classassociation
JOIN students
ON classassociation.UserID = Students.UserID
JOIN classes
ON classassociation.ClassID = classes.ClassID
WHERE classassociation.ClassID = 1
GROUP BY ClassName;
Now you will get a result set with one row for each ClassName, with two columns:
ClassName | UserIds
---------------------
Methodology | 1,2
Then you can write a simple php loop to take each row in the query and generate a table row in your html.
If you look at the manual for GROUP_CONCAT, you can see that you can also set the order that the userIds are grouped in, which might be useful.
The php loop is pretty simple once you have your query results; you just need to create a table and then add a row for each result:
/*assume your mysql query has returned an array of objects named $result */
// in your html document, create your table with its header
print '<table><thead><tr><th>Class Name</th><th>UserIds</th></tr></thead>';
print '<tbody>';
// now loop through your query results and put stuff into the table
// of course you can monkey around with the table format and what goes in each cell
foreach($result as $row) {
print '<tr><td>'.$row->ClassName.'</td><td>'.$row->UserIds.'</td></tr>';
}
print '</tbody></table>';
That's a very simple example, but hopefully demystifies the process somewhat.
Your particular case looks like the query is actually to get the contents of one cell in your table; you can either do a much grander query that groups by time and day of week, or you can do little queries and store the results in nested arrays that model how you want your table to look. The html output is structurally the same, but you would have a php loop for each table cell.
To have table with each cell showing the result of a separate query, consider something like the following pseudocode:
$days = array('Monday', 'Tuesday',...'Friday');
$times = array('9', '10'...);
$weekResults = array();
foreach($days as $day) {
$weekResults[$day] = array();
foreach($times as $time) {
$weekResults[$day][$time] = doQuery($day, $time);
}
}
// now you have nested arrays with a result set for each table cell.
// Rendering the table, you just use the same loops:
renderTableHeader(); // all the <table><thead> stuff
foreach($weekResults as $day) {
print '<tr>'
foreach($day as $time) {
print '<td>';
// output the data from your query like above
// if the formatting is complex, you can even put another table inside the <td>.
print '</td>';
}
print '</tr>';
}
renderTableFooter(); // close tbody and table tags
Hope that helps!

Inserting Data to a Table Retrieved from Two Merged Tables

I have two courses. In each course there are several assignments. A student can follow both courses.
I have the following tables:courses,student_courses,course1
My courses table has st_index,assignmnet_no,marks,course_no as the fields
and student_courses table has st_index,course1,course2 where 1is inserted if the student follows course1 or course2 .
Table course1 has Student_Index, Assignment1, Assignment2,Assignment3 as fields.
I have inserted my data into tables courses,student_courses. By retrieving data from these I want to come up with course1 table.course1
should look as follows:
Here's my code:
if($_SESSION['user']['course']=="Course1"){
$result=mysql_query("SELECT student_index FROM student_courses WHERE course1=1");
while($index=mysql_fetch_array($result)){
echo $index[0];
echo"<br>";
$result2=mysql_query("SELECT * FROM courses WHERE course_no='Course1' AND st_index='$index[0]'");
while($i2=mysql_fetch_array($result2)){
$ass_no=$i2['assignment_no'];
if($ass_no=='1'){
echo $index[0];
$result3=mysql_query("INSERT INTO course1(Student_Index,Assignment1) VALUES('$index[0]','$i2[marks]')");
}
if($ass_no=='2'){
echo $index[0];
$result4=mysql_query("INSERT INTO course1(Assignment2) VALUES('$i2[marks]')");
}
if($ass_no=='3'){
$result5=mysql_query("INSERT INTO course1(Assignment3) VALUES('$i2[marks]')");
}
}
}
}
?>
The problem is for course1 only the first student_index assignment values gets inserted. In there also for the same student_index the values gets inserted into two separate rows. What I am trying to do is when we consider a row in course1, which is identified by student_index that row should have all the assignment marks of that student. How can I achieve this?
That is say I have two records that match the conditions for the table course1 as 945,568.
In the course1 it only gets inserted records for 965 and it also looks like below. . The two rows should be one, under same index_no
In order to check what is going wrong inside first while loop I used echo $index[0] . It prints 945,568 both. But in the if statements inside the other while loop only 945 gets printed. That is when the loop is run for the second time I think the line $result2=mysql_query("SELECT * FROM courses WHERE course_no='Course1' AND st_index='$index[0]'"); doesn't get executed.
The problem is that in SQL, INSERT always adds a new row. You've inserted a row for each mark, but only provided a Student_Index for one of them (thus the empty indexes on subsequent rows). What you want is the UPDATE command.
So let's just use INSERT once to create a row for each student, just before the inner WHILE:
INSERT INTO course1(Student_Index) VALUES('$index[0]')
and then fill the fields by replacing your INSERT statements with (e.g. for assignment 1):
UPDATE course1 SET assignment1 = '$i2[marks]' WHERE Student_Index = '$index[0]'
Alternatively, you can accomplish this in SQL alone with the following:
CREATE TABLE course1
SELECT s1.st_index,
a1.marks AS Assignment1,
a2.marks AS Assignment2,
a3.marks AS Assignment3
FROM courses a1, courses a2, course a3
WHERE a1.course_no = 1
AND a2.course_no = 1
AND a3.course_no = 1
AND a1.assignment_no = 1
AND a2.assignment_no = 2
AND a3.assignment_no = 3
AND a1.st_index = a2.st_index
AND a1.st_index = a3.st_index;
We've joined the course table three times to select out the three rows where the three marks reside for with course_no=1 and constrained them to be the same student in all three rows. This will return one row for each student. Also, With this solution there is no need for a reference to the student_courses table at all since you can infer the enrollment of a student in a course by the presence of marks in the course table.

Better Way to return multiple SQL Queries in one PHP page

I am writing a website to compare cars to learn and understand PHP. I have a sql table of cars - one are of say ford - which as a company id of 1 in my another table. There is also a ModelLinkNo column in the table to link say saloon cars from Ford to saloon cars from BMW (which has a companyId of 2).
I want to display first a list of all ford company cars so my query is like below:
$getFordCars = sprintf("SELECT * FROM Cars WHERE CompanyId = '1'");
I then have multiple other querys below to bring back other cars which are off the same model - so like below:
$getSaloonCars = sprintf("SELECT * FROM CarsWHERE (CompanyId != '1' AND ModelLinkNo = '1')");
There are then other querys for get 4*4s get Hatchback, convertible, etc.
The data comes back from DB fine and I am wrting it to array as below:
<?php
$fordCars = array();
$otherSaloonCars = array();
$i = 0;
while($row = mysql_fetch_array($fordCarsResult))
{
$fordCars [$i]= $row['ModelName'];
$i++;
}
$j = 0;
while($row2 = mysql_fetch_array($otherSaloonCarsResult))
{
$otherSaloonCars [$j]= $row2['ModelName'];
$j++;
}
?>
The above works and then I can retrieve the data for displaying further in my page - however is there a better way of doing this rather than having multiple while loops - as when I return all convertible models that would be another query and return 4*4's that will be another query and using the pattern I am using now that would result in writing a while loop for each query to write the results into an array
Well, how about just downloading every ford car, and check on your backend site, if CompanyId is 1, or not, and pushing the data to the given array?
Also consider looking up for JOIN-ing your Cars table to itself, if needed.

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

Categories