Grouping row elements into one column using SQL - php

My current table is fetching content from the database like this but I would like to combine the rows so that all the Room Preference's are displayed in one row rather than over several. How can I go about doing this? As a result the table below would have only two rows.
The Room Preference information is being inferred from ts_roompref.
Here is my code so far:
$sql = "SELECT
*
FROM ts_request
INNER JOIN ts_day
ON ts_request.day_id = ts_day.id
INNER JOIN ts_period
ON ts_request.period_id = ts_period.id
INNER JOIN ts_allocation
ON ts_request.id = ts_allocation.request_id
INNER JOIN ts_roompref
ON ts_request.id = ts_roompref.request_id
WHERE ts_request.round=:round
AND ts_request.dept_id=:dept
ORDER BY ts_request.module_id ASC";
}
$stm = $pdo->prepare( $sql );
$stm->execute( array( ':round' => 'P', ':dept' => $loggedin_id ) );
$rows = $stm->fetchAll();
foreach ($rows as $row)
{
echo '<tr align="center">';
echo '<td>'.$row['module_id'].'</td>';
echo '<td>'.$row['day'].'</td>';
echo '<td>'.$row['period'].'</td>';
echo '<td>';
if ($row['room_id']=="0")
{
echo "Any";
}
else
{
echo $row['room_id'];
}
echo '</td>';
echo '<td>'.$row['status'].'</td>';
echo '</tr>';

Well, I guess your trying to do it in SQL, but if you wanted to do it in your PHP you could loop over the rows watching for changes to Module Code. Pseudo code something like...
$newrows = array()
$tmpCode = ""
foreach $rows as $row
if $tmpCode != $row['module_code'] {
$tmpCode = $row['module_code']
$newrows[] = $row
} else {
$newrows[count($newrows) - 1]['room_preference'] .= $row['room_preference']
}
}
...rough, but you get the idea.

If you want to do it in SQL, can't you do a GROUP_CONCAT on room_preference and GROUP BY the other 4 fields?

Related

PHP/MYSQL Sorting an echo table of mysql data

I've got a piece of coursework to build a php site using mysql.I need to be able to sort a table of data based on it's columns. The data is retrieved from a mysql DB using PDO. I then just echo a table while looping through each row of data
Any Ideas as to how I can sort the data by columns? Preferably I'd like to be able to sort the data (ascending) by clicking on the table headers. But i'm open to Ideas.
Code Below:
PHP:
function displayBooks($data){
echo "<table id= \"allBooks\">";
echo "<th>Book ID</th><th>Title</th><th>Description</th><th>In Stock</th><th>Price</th><th>Cateogry</th>";
#foreach($data as $row)
{
echo "<tr>";
echo "<td>".$row['bookID']."</td>";
echo "<td>".$row['title']."</td>";
echo "<td>".$row['description']."</td>";
echo "<td>".$row['quantity']."</td>";
echo "<td>£".$row['price']."</td>";
echo "<td>".$row['name']."</td>";
echo "</tr>";
}
echo "</table>";
....
//Retrieve all books
$all_books_query = "SELECT b.bookID,b.title,b.description,b.quantity,b.price,c.name FROM Books b
INNER JOIN Book_Category bc ON bc.bookID = b.bookID
INNER JOIN Category c ON c.catID = bc.catID
GROUP BY b.bookID;";
$rows = $db->query($all_books_query)->fetchAll();
I've got a whole lot more PHP in the rest of the page. Not sure what else I need to include in this to make more sense of the problem, but any ideas will help.
Set up a mechanism to send the user's sorting requirements back to the server (query param? post?), and use those requirements to set up an ORDER BY clause in your MySQL query.
Here's a simple, non_robust implementation
You must make some active links, with params, like this:
function displayBooks($data){
echo "<table id= \"allBooks\">";
echo "<th><a href='index.php?col=1&order_by=1'>Book ID ASC</a>|<a href='index.php?col=1&order_by=2'>Book ID DESC</a></th><th><a href='index.php?col=2&order_by=1'>Title ASC</a>|<a href='index.php?col=2&order_by=2'>Title ID DESC</a></th>";
#foreach($data as $row)
{
echo "<tr>";
echo "<td>".$row['bookID']."</td>";
echo "<td>".$row['title']."</td>";
echo "</tr>";
}
echo "</table>";
And the second poart of script
//Retrieve all books
$order_by = 'ASC';
switch ( (int)$_GET['order_by'] ) {
case 1:
$order_by = 'ASC';
break;
case 2:
$order_by = 'DESC';
break;
}
$col= "bookID";
switch ( (int)$_GET['col'] ) {
case 1:
$col = 'bookID';
break;
case 2:
$col = 'title';
break;
}
$all_books_query = "SELECT b.bookID,b.title,b.description,b.quantity,b.price,c.name FROM Books b
INNER JOIN Book_Category bc ON bc.bookID = b.bookID
INNER JOIN Category c ON c.catID = bc.catID
GROUP BY b.bookID
ORDER BY $col $order_by";
$rows = $db->query($all_books_query)->fetchAll();

Compare MySQL data with another table

This code below echoes out 8 names from tableOne, but I want to compare those names with 8 names in another table. I want to compare the rows echoed in $row['weight'] with tableTwo, and if the results don't match, then add a <span class="strike"> </span> to the result echoed in $row['weight'].
How do I go about adding an if/else to $row['weight'] compare each name with the names in another table?
$result = mysqli_query($con,"SELECT * FROM tableOne LIMIT 0, 8");
$i = 1;
while($row = mysqli_fetch_array($result)) {
echo $i. " - " . $row['weight'] . '<br>';
$i++;
}
Here is some simple code to get you started:
$result = mysqli_query($con,"SELECT * FROM tableOne LIMIT 0, 8");
$result2 = mysqli_query($con,"SELECT * FROM tableTwo LIMIT 0, 8");
$i = 1;
while($row = mysqli_fetch_array($result)) {
$value1 = $row['weight'];
$row2 = mysqli_fetch_array($result2);
$value2 = $row2['weight'];
echo $i . " - table 1: ";
echo $value1;
echo ", table 2: - ";
if ($value2 != $value1) {
echo '<span class="strike">$value2</span>';
} else {
echo $value2;
}
echo '<br>';
$i++;
}
You can make the code smarter, to handle cases where there aren't 8 values to compare, and to display the values in an HTML table too, but hopefully this can get you started.
Try this:
$sql="select * from tableone to left join tabletwo tw on to.weight=tw.weight ";
This query will return all the rows in tableone which matches and empty rows for the ones where the weight dont match.
So in your php code:
while($row = mysqli_fetch_array($result)) {
if(empty($row['weight'])){
echo '<span class="strike">$row[weight]</span>';
}
}
This would work with any dynamic number of records in the tables.
How about keeping the values ($row[]) in one array($tableOne) and doing the same thing for table two ($tableTwo) and then perform your comparison in foreach()? (For the sake of simplicity, if you don't want any joins)

Join two MySQL tables and group result with php

I have the following code to populate cities in a table.
$cities_query = "SELECT city_name FROM city_selection";
$cities_result = mysql_query($cities_query);
echo "<table>";
while ($row = mysql_fetch_assoc($cities_result))
{
echo "<tr>";
echo "<td>".$row['city_name'] . "</td>";
echo "</tr>";
}
echo "</table>";
Now I need to group every city by a region so I created the table called city_region_selection and added a Foreign key from the new column "region_id" in the city_selection table to region_id in the new table.
I'm now struggling to present this data in a nice html table using PHP.
Is it even possible to populate first a table row with region_name and then some subrows containing cities from that region? Please see this image for details:
You just have to do a little preprocessing:
/* SQL
SELECT
city_name,
region_name
FROM
city_selection
NATURAL JOIN city_region_selection
SQL */
$regions = array();
while ($result->fetch()) {
if (!isset($regions[$result->region_name])) {
$regions[$result->region_name] = array();
}
$regions[$result->region_name][] = $result->city_name;
}
Alternate Method with SQL focus
/* SQL
SELECT
region_name,
GROUP_CONCAT(city_name SEPARATOR ',') cities
FROM
city_selection
NATURAL JOIN city_region_selection
GROUP BY
region_name
*/
$regions = array();
while ($result->fetch()) {
$regions[$result->region_name] = explode(',', $result->city_name);
}
Help
Note that the while syntax is just abridged. You would probably replace it with
while ($row = mysql_fetch_assoc($cities_result)) {
$regions[$row['region_name']] = explode(',', $row['city_name']);
}
... for example
Once regions is built, simply do this:
foreach ($regions as $region => $cities) {
echo "<tr><td>$region</td></tr>";
foreach ($cities as $city) {
echo "<tr><td class="tabbed">$city</td></tr>";
}
}

More efficient hierarchy system

I am trying to code a hierarchy detection script, I've already written the script, but can only go down 4 levels. Is there a way to condense this to a few lines that will work with an infinite amount of levels?
This script is basically the same code copy and pasted 4 times
<?php
function listCategories($name, $disable_status = 0, $show_nums = 0) {
echo "<select name='".$name."'>";
$result = mysql_query("SELECT * FROM categories") or die(mysql_error());
while($row = mysql_fetch_array($result)) {
if($row['parent_id']==0) {
$result2 = mysql_query("SELECT * FROM categories WHERE parent_id=".$row['id']) or die(mysql_error());
echo "<option value='".$row['id']."'";
if($disable_status==1&&isParent($row['id'])){
echo " disabled='disabled'";
}
echo ">".$row['name']."</option>";
while($row2 = mysql_fetch_array($result2)) {
$result3 = mysql_query("SELECT * FROM categories WHERE parent_id=".$row2['id']) or die(mysql_error());
echo "<option value='".$row2['id']."'";
if($disable_status==1&&isParent($row2['id'])){
echo " disabled='disabled'";
}
echo ">- ".$row2['name']."</option>";
while($row3 = mysql_fetch_array($result3)) {
$result4 = mysql_query("SELECT * FROM categories WHERE parent_id=".$row3['id']) or die(mysql_error());
echo "<option value='".$row3['id']."'";
if($disable_status==1&&isParent($row3['id'])){
echo " disabled='disabled'";
}
echo ">-- ".$row3['name']."</option>";
while($row4 = mysql_fetch_array($result4)) {
echo "<option value='".$row4['id']."'>[".$row4['id']."] --- ".$row4['name']."</option>";
}
}
}
}
}
echo "</select>";
}
function isParent($cat_ID) {
$result = mysql_query("SELECT * FROM categories WHERE parent_id=".$cat_ID) or die(mysql_error());
if(mysql_num_rows($result)==0) {
return FALSE;
} else {
return TRUE;
}
}
My table structure for categories is
id, name, parent_id
If the category has no parent, the parent_id will be 0, or else, it would be the id of the category of it's parent.
All help is appreciated.
I guess something along these lines should do (untested, must be adapted to your needs):
$q = mysql_query("SELECT id, parent_id, name FROM categories");
while ($r = mysql_fetch_row($q)) {
$names[$r[0]] = $r[2];
$children[$r[0]][] = $r[1];
}
function render_select($root=0, $level=-1) {
global $names, $children;
if ($root != 0)
echo '<option>' . strrep(' ', $level) . $names[$root] . '</option>';
foreach ($children[$root] as $child)
render_select($child, $level+1);
}
echo '<select>';
render_select();
echo '</select>';
an even funkier way of doing this is by using SQL stored procedures, but it may be way overkill in this case...
This isn't an answer but instead of using many selects you can use many left joins to traverse 4 hierarchies. Instead of so many row of codes it's just this single query:
select a.id,a.parent_id,b.id,b.parent_id,c.id,c.parent_id,d.id,d.parent_id from a left join b ON a.id = b.parent_id left join c on b.id=c.parent_id left join d on c.id=d.parent_id;
You can use my query with a single table, too, because you can alias a table name:
left join mytable as c on c.id=d.parent_id ... ...
But unfortunetley mysql doesn't support recursive selects. Maybe try another database?

Getting the table name of a row from a mysql query that grabs from multiple tables

I have some PHP/MySQL code that pulls data from multiple different tables (using Inner Joins). It looks something like this:
$query = "SELECT * FROM table1 INNER JOIN table2 USING (key)";
$data = mysqli_query($dbc, $query);
while ($row = mysqli_fetch_array($data)) {
echo $row[1];
}
So the code is simple enough, but what I want to do is echo the table each row is in inside of that while loop, since it could be in one of 2 tables.
I saw there was some old mysql functions like mysql_field_table and mysql_tablename that would do the trick, but they all seem to be deprecated.
Would appreciate any advice on how to accomplish this.
You could select the data with a special identifier for each table instead of using *
select table1.row1 as t1r1, table2.row1 as t2r1,..... from .....
And inside php you could look for the strings t1 and t2 and do stuff accordingly.
What you can do is echo more than one field from your result table (which hopefully now contains information from both the tables.
$query = "SELECT * FROM table1 INNER JOIN table2 USING (key)";
$data = mysqli_query($dbc, $query);
while ($row = mysqli_fetch_array($data))
{
echo $row[1] . " " . $row[2];
}
...and then $row[3] etc...
Or access the column name/field by the column name or alias provided by AS.
$query = "SELECT * FROM table1 INNER JOIN table2 USING (key)";
$data = mysqli_query($dbc, $query);
while ($row = mysqli_fetch_assoc($data))
{
echo $row["c_name1"] . " " . $row["c_name2"];
}
Where "c_name1" and "c_name2" are your column names.
Use an AS keyword to rename all columns.
$select_clause = '';
$tables = array('tblA', 'tblB');
foreach($tables as $tbl) {
mysql_query('SHOW COLUMNS FROM ' . $tbl);
while ($row = mysql_fetch_assoc())
$select_clause .= '`'.$tbl.'`.`'.$row['Field'].'` AS `'.$tbl
.'_'.$row['Field'].'`,';
}
$select_clause = substr($select_clause, 0, -1);
mysql_query('SELECT '.$select_clause.' FROM /*...*/ ');

Categories