I have a database structure something like the following:
Table A: PersonId, GroupId
Table B: GroupId, ParentGroupId
Given a PersonId, I want to find the Ids of all people in parent groups of that person's group.
First I select the ParentGroupId for the given PersonId, by joining with B. Then I do a while loop, selecting and recording the PersonId from A based on the GroupId returned in the previous search, and continue the loop by obtaining the next ParentGroupId from B.
Is this an efficient way to do this search, or is there an option that does not involve a while to "bubble up" in this manner?
(this is a simplified version of the actual scenario, changing the schema is not an option)
$sql = 'SELECT ParentGroupID FROM A WHERE PersonId = ' . $id;
$result = $db->query($sql);
$row = $db->fetch_array($result);
$parent_group = $row['ParentGroupId'];
if(!is_null($parent_group)) {
$parent_ids = array();
while($parent_group > 0) {
//is there a way to do this where I retrieve all managers <= lvl 6 at once, so I don't have to loop in order to 'tier up'?
$sql = 'SELECT ParentGroupID, PersonID
FROM B
INNER JOIN A on ParentGroupID = A.GroupID
WHERE ParentGroupID = ' . $parent_group;
$result = $db->query($sql);
$row = $db->fetch_array($result);
$parent_group = $row['ParentGroupID'];
$parent_ids[] = $row['PersonID'];
}
}
Combining your two queries into one would be more efficient:
$sql = 'SELECT ParentGroupID, PersonID
FROM B
INNER JOIN A on ParentGroupID = A.GroupID
WHERE ParentGroupID IN (
SELECT ParentGroupID FROM A WHERE ParentGroupID > 0
AND PersonId = ' . $id .')' ;
Related
I have a nested while statement that gives the results I need but is very inefficient and takes forever to run? Any thoughts on how these could be combined?
I first create a temporary table with all the data I need from a larger table called student grades. I then get the students and course names because I want to group these for each report. I then look for each student then get the scores for each assignment. I also want to get the average of the only of the last three assignments for each particular learning outcome ID.
//MYSQL query to create temp table
$qryTmp = "CREATE TEMPORARY TABLE IF NOT EXISTS tmp AS (SELECT studentsisid,coursename,assessmenttitle,studentname,outcomescore,recordid,learningoutcomeid,learningoutcomename,assessmentid
from studentgrades
WHERE studentsisid LIKE '$studentid' AND coursename LIKE '$coursename')";
mysql_query($qryTmp);
//MYSQL query Coursename and student name
$qryCourse = "SELECT studentsisid,coursename,studentname
from tmp
WHERE studentsisid LIKE '$studentid' AND coursename LIKE '$coursename' GROUP BY studentsisid,coursename ORDER by studentname,coursename";
$resultCourse=mysql_query($qryCourse);
while ($rowCourse = mysql_fetch_assoc($resultCourse)) {
$studentid = $rowCourse['studentsisid'];
$name = $rowCourse['studentname'];
$coursename = $rowCourse['coursename'];
//MYSQL query Learning Outcome ID
$qryLID ="SELECT outcomescore,learningoutcomeid,count(RecordID) as assessmentcount
from tmp
WHERE studentsisid = '$studentid' AND coursename='$coursename'
Group by studentsisid,coursename, learningoutcomeid ORDER BY studentname, coursename";
$resultLID=mysql_query($qryLID);
while ($rowLID = mysql_fetch_assoc($resultLID)) {
$learningoutcomeid = (int)$rowLID['learningoutcomeid'];
$assessmentcount = (int)$rowLID['assessmentcount'];
//MYSQL query recent 3
$qryRecent3 = "SELECT avg(outcomescore) as recentscoreavg
FROM
(SELECT outcomescore FROM tmp WHERE
studentsisid='$studentid' AND coursename='$coursename' AND learningoutcomeid='$learningoutcomeid'
ORDER BY AssessmentID DESC LIMIT 3) as r";
$resultRecent3=mysql_query($qryRecent3);
while ($rowRecent3 = mysql_fetch_assoc($resultRecent3)) {
$recentscoreavg = number_format($rowRecent3['recentscoreavg'], 1);
$assessmentcount = $rowRecent3['recentover3'];
}
}
}
I have a database with several tables. I'm able to query IDs from a single table. What I'd like to do is Use those IDs to query another tables IDs, then use these new IDs to query fields from the final table. Here is what I am currently doing:
Here is how I acquire the first set of IDs:
$returnedPost = mysqli_query($con, "SELECT Region_ID FROM Region WHERE RegionName='" . $queryVar . "'");
function resultToArray($result) {
$rows = array();
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
return $rows;
}
$rows = resultToArray($returnedPost);
//$rows[x]['Region_ID'];//returns Region_ID 1...n
I'd like to use the IDs in $rows to be able to query a new set of IDs from other tables as follows:
$newTbl = mysqli_query($con, "SELECT Location_ID FROM Location WHERE Region_ID=" . $rows[$x]['Region_ID']);
$rows2 = resultToArray($newTbl);
$finalTbl = mysqli_query($con, "SELECT Field1, Field2 FROM Posts WHERE Location_ID=" . $rows2[$x]['Location_ID']);
Can someone please tell me how I can accomplish this? Thanks.
you can use INNER JOIN in one query to get at this data, maybe something like this
SELECT P.Field1,P.Field2
FROM Region R
INNER JOIN Location L ON R.Region_ID = L.Region_ID
INNER JOIN Posts P ON L.Location_ID = P.Location_ID
WHERE R.RegionName = Your_Region_QueryVar
I'm trying to show stuff queried from two tables, but on one html table. Data is shown for the last 30 days, based on which, an html table is being generated.
Currently I'm stuck using two queries and generating two html tables:
$query1 = mysqli_query( $con, "SELECT date, stuff* " );
while( $record = mysqli_fetch_array( $query1 ) ){
echo '<html table generated based on query>';
}
$query2 = mysqli_query( $con, "SELECT date, other stuff*" );
while( $record = mysqli_fetch_array( $query2 ) ){
echo '<another html table generated based on query2>';
}
Is there a possibility to show both queries on one html table instead?
Note that it gets tricky since we have dates on one table which are not necessarily found in the second table or vice-versa.
Thanks for the support guys. So far I'm stuck at this:
SELECT * FROM user_visit_logs
LEFT JOIN surfer_stats ON user_visit_logs.date = surfer_stats.date
UNION
SELECT * FROM user_visit_logs
RIGHT JOIN surfer_stats ON user_visit_logs.date = surfer_stats.date
The query completes, but the 2nd table fields are all null:
Furthermore, it breaks when I add additional clause like:
WHERE user_id = '{$_SESSION['user_id']}' ORDER BY date DESC LIMIT 30
I think you are after FULL OUTER JOIN concept:
The FULL OUTER JOIN keyword returns all rows from the left table (table1) and from the right table (table2)
In which you may use common dates as a shared row.
So the query will get to simple one:
$query = "
SELECT table1.date, stuff
FROM table1
LEFT OUTER JOIN table2 ON table1.date = table2.date
UNION
SELECT table2.date, other_stuff
FROM table1
RIGHT OUTER JOIN table2
ON table1.date = table2.date
";
$result = mysqli_query( $con, $query );
while( $record = mysqli_fetch_array( $result ) ){
echo '<html table generated based on query>';
}
Example
This is an schematic diagram of FULL OUTER JOIN concept:
After running into quite a few bumps with this one, I finally managed to merge 2 columns from each table and also to use where and sort clauses on them with the following query:
( SELECT user_visit_logs.user_id,user_visit_logs.date,unique_hits,non_unique_hits,earned,sites_surfed,earnings FROM user_visit_logs
LEFT OUTER JOIN surfer_stats ON user_visit_logs.user_id = surfer_stats.user_id AND user_visit_logs.date = surfer_stats.date where user_visit_logs.user_id = 23 ORDER BY date DESC LIMIT 30 )
UNION
( SELECT surfer_stats.user_id,surfer_stats.date,unique_hits,non_unique_hits,earned,sites_surfed,earnings FROM user_visit_logs
RIGHT OUTER JOIN surfer_stats ON user_visit_logs.user_id = surfer_stats.user_id AND user_visit_logs.date = surfer_stats.date where user_visit_logs.user_id = 23 LIMIT 30 )
Simplified, "user_visit_logs" and "surfer_stats" were the 2 tables needed to be joined.
Absolutely. Just pop them both into a variable:
$data = '';
$query = mysqli_query($con,"SELECT date, stuff* ");
while($record = mysqli_fetch_array($query)) {
$data.= '<tr><td>--Your Row Data Here--</td></tr>';
}
$query2 = mysqli_query($con,"SELECT date, other stuff*");
while($record = mysqli_fetch_array($query2)) {
$data .= '<tr><td>--Your Row Data Here--</td></tr>';
}
echo "<table>$data</table>";
Instead of using echo in your loop, you're just storing the results in $data. Then, you're echoing it out after all data has been added to it.
As for your second point, it's not a big deal if fields don't exist. If they're null, you'll just have a column that doesn't have data in it.
Here's an example with fake column names:
$data = '';
$query = mysqli_query($con,"SELECT date, stuff* ");
while($record = mysqli_fetch_array($query)) {
$data.= "<tr><td>{$record[id]}</td><td>{$record[first_name]}</td><td>{$record[last_name]}</td></tr>";
}
$query2 = mysqli_query($con,"SELECT date, other stuff*");
while($record = mysqli_fetch_array($query2)) {
$data .= "<tr><td>{$record[id]}</td><td>{$record[first_name]}</td><td>{$record[last_name]}</td></tr>";
}
echo "<table><tr><th>ID</th><th>First Name</th><th>Last Name</th></tr>$data</table>";
I have a feeling I may have misunderstood the need. If so, I apologize. If you can elaborate just a bit more I can change my answer :)
I have a script designed to print out values of students who have accrued more than 3 tardies. I want this script to print out both the student name, and the amount of times they've been tardy, but so far I've been only able to print out their names with the following script:
$sql = "select DISTINCT StudentID,classid,date from attendance_main where status = 'Tardy' AND classid like '%ADV%'";
$result = mysql_query($sql) or die (mysql_error());
while($row=mysql_fetch_array($result)) {
$studentid = $row['StudentID'];
$sql2 = "select distinct StudentID,classid,date from attendance_main where StudentID = '$studentid' AND status = 'Tardy' AND classid like '%ADV%'";
$result2 = mysql_query($sql2) or die (mysql_error());
while($row2=mysql_fetch_array($result2)) {
$tardycount = mysql_num_rows($result2);
$studentid = $row2['StudentID'];
if($tardycount >= 3) {
$sql3 = "select * from students where rfid = '$studentid'";
$result3 = mysql_query($sql3) or die (mysql_error());
while($row3=mysql_fetch_array($result3)) {
$fname[] = $row3['fname'];
}
}
}
}
$newdata = array_unique($fname);
foreach ($newdata as $value) {
echo $value;
}
I can't think of how to intuitively do this. Keeping it all in the while loop didn't work (I had multiple results coming up for the same students despite requesting unique entries) so using array_unique was the only method I could think of.
Thanks for any help!
Something like this:
SELECT
attendance_main.StudentID,
students.fname,
COUNT(attendance_main.*) AS `times_tardy`
FROM
attendance_main
INNER JOIN
students
ON
attendance_main.StudentID = students.rfid
WHERE
attendance_main.status = 'Tardy'
AND
attendance_main.classid like '%ADV%'
GROUP BY
attendance_main.StudentID
HAVING
`times_tardy` > 3
Joining the two tables gets you the tardy count and student's name in one query, and the GROUP BY and HAVING clause that get you only the students with more than 3 tardy entries.
You can (and should) do almost everything in SQL. It should look something like this.
select StudentID, classid, date count(*)
from attendance_main
where status = 'Tardy' AND classid like '%ADV%'"
left join student on student.rfid = attendance_main.StudentId
group by StudentId
having count(*) > 3;
Here's how it works.
select the results you want to work with:
select StudentID, classid, date count(*)
from attendance_main
where status = 'Tardy' AND classid like '%ADV%'"
Join the students to your result set on the common id
left join student on student.rfid = attendance_main.StudentId
group everything by student. We use count(*) to get the number of items. We know we're only dealing with tardies because of the where clause in the select.
group by StudentId
limit the results to only tardies above 3 with the having claues (this is like a where clause for the group by)
having count(*) > 3;
Mysql query and PHP code that I'm using to get users from the database that meet certain criteria is:
$sql = mysql_query("SELECT a2.id, a2.name FROM members a2 JOIN room f ON f.myid = a2.id
WHERE f.user = 1 AND a2.status ='7' UNION SELECT a2.id, a2.name FROM members a2
JOIN room f ON f.user = a2.id WHERE f.myid = 1 AND a2.status ='7' GROUP BY id")
or die(mysql_error());
while ($r = mysql_fetch_array($sql))
{
$temp[] = '"'.$r[0].'"';
}
$thelist = implode(",",$temp);
The query that follows get the list of members with new galleries by using array from the previous query.
$ft = mysql_query("SELECT id, pic1 FROM foto WHERE id IN ($thelist) AND
pic1!='' ORDER BY date DESC LIMIT 10");
while ($f = mysql_fetch_array($ft))
{
echo $f['id']." - ".$f['pic1']."<br/>";
}
These queries working fine but I need to get the name for every user listed in second query. This data is in the first query in the column name. How can I get it listed beside '$f['id']." - ".$f['pic1']'?
While I might just alter the first query to pull the galleries at the same time, or change the second query to join and get the name, you could keep the same structure and change a few things:
In the loop after the first query when building $temp[], also build a lookup table of user id to user name:
$usernames[$r[0]] = $r[1];
Then in your output loop, use the id (assuming they are the same!) from the second query to call up the user name value you stored:
echo $f['id'] . " - " . $f['pic1'] . " - " . $usernames[$f['id']] . "<br/>";