One Day Agenda with tables, php and MySQL - php

I need to create a one day agenda, with the reservations of our study rooms in it.
This agenda should show all the rooms and show the occupied times, like:
8:00 8:15 8:30 8:45 9:00 9:15 9:30 ...
Room 1 | [username ] [username 2
Room 2 | [username 3 ]
Room 3 |[username 4 ] [username 5 ...
...and so on
So it should be clear from the table that Room 1 is occupied from 8:15-9:00 and 9:30-..., Room2 occupied from...
But also which times the study rooms are free.
And I'm a bit stuck at the mo.
This is the code I already have, but it's incomplete:
<table>
<tr>
<?php
$roomlist = "SELECT * FROM rooms";
$roomresult = mysql_query($roomlist);
while($roomnames=mysql_fetch_array($roomresult)) {
$roomid=$roomnames['roomid'];
$roomname=$roomnames['roomname'];
?>
<td><?= $roomname;?></td>
<?php
$query = "SELECT * FROM reservations WHERE roomid = '$roomid' AND (start LIKE '%" . $agenda . "%') ORDER BY start,roomid,end ";
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_array($result)){
$username=$row["username"];
$aantal=$row["numberingroup"];
$reservationid=$row["reservationid"];
$start=$row["start"];
$end=$row["end"];
$roomid=$row["roomid"];
$startdate = explode(" ",$start);
$startdate[0] = explode("-",$startdate[0]);
$startdate[1] = explode(":",$startdate[1]);
$StartFormat = mktime($startdate[1][0],$startdate[1][1],$startdate[1][2],$startdate[0][1],$startdate[0][2],$startdate[0][0]);
$StartDate = date("d/m/Y",$StartFormat);
$StartTime = date("H:i",$StartFormat);
$stopdate = explode(" ",$end);
$stopdate[0] = explode("-",$stopdate[0]);
$stopdate[1] = explode(":",$stopdate[1]);
$StopFormat = mktime($stopdate[1][0],$stopdate[1][1],($stopdate[1][2]+1),$stopdate[0][1],$stopdate[0][2],$stopdate[0][0]);
$StopDate = date("d/m/Y",$StopFormat);
$StopTime = date("H:i",$StopFormat);
$cell = (strtotime($StopTime)-strtotime($StartTime))/(60*15); //a quarter per cell
?>
<td><?= $username . " " . $cell;?></td>
<?php } ?>
</tr>
<?php
}
mysql_close();
?>
</table>`
$cell is calculated because I figured I needed to know how many cells a reservation needed (so one per quarter), but I'm stuck now on how to calculate the free slots, and how to implement all that in a table.
UPDATE:
structure of table 'reservations'
reservationid,start,end,roomid,username
41,2014-01-06 08:00:00.000000,2014-01-06 08:59:59.000000,28,stefdg

As basic example piece of SQL to give you some idea of how to return a range of possible time slots / room combinations and join that against your reservations
SELECT *
FROM rooms
CROSS JOIN
(
SELECT DATE_ADD(DATE_ADD(CURDATE(), INTERVAL 8 HOUR), INTERVAL ((units.a + tens.a * 10) * 15) MINUTE) AS TimeSlotStart
FROM
(SELECT 0 AS a UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units,
(SELECT 0 AS a UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
WHERE units.a + tens.a * 10 <= 40
) TimeSlots
LEFT OUTER JOIN reservations ON rooms.roomid = reservations.roomid AND TimeSlots.TimeSlotStart >= start AND TimeSlots.TimeSlotStart < end
Note, not quite sure what your end value applies to (ie, if a reservation finishes at 9:00, I am assuming that has nothing to do with the time slot that starts at 9:00)
EDIT - scraipt based on yours to output the table of details. This is just putting out xxx for any time slot that a room is occupied for.
<html>
</html>
<body>
<table>
<?php
$link = mysqli_connect('localhost', 'root', '');
$db_selected = mysqli_select_db($link, 'test');
$sql = "SELECT a.timeslot_start, b.roomid, b.roomname, TIME(c.start) AS start
FROM timeslots a
CROSS JOIN rooms b
LEFT OUTER JOIN reservations c
ON b.roomid = c.roomid
AND a.timeslot_start >= TIME(c.start)
AND a.timeslot_start < TIME(c.end)
ORDER BY b.roomid, a.timeslot_start";
$roomresult = mysqli_query($link, $sql) or die(mysql_error());
while($roomnames=mysqli_fetch_assoc($roomresult))
{
$room_bookings[$roomnames['roomid']][] = $roomnames;
}
$first_room = reset($room_bookings);
echo "<table>";
$FirstRoomDetails = reset($room_bookings);
$Header = array(0=>array("<td></td>"), 1=>array("<td></td>"));
foreach($FirstRoomDetails AS $aRoomTimeSlot)
{
$TimeSlotSplit = explode(':', $aRoomTimeSlot['timeslot_start']);
if ($TimeSlotSplit[1] == '00')
{
$Header[0][] = "<td colspan='4'>".$TimeSlotSplit[0]."</td>";
}
$Header[1][] = "<td>".$TimeSlotSplit[1]."</td>";
}
echo "<tr>".implode('', $Header[0])."</tr>\r\n";
echo "<tr>".implode('', $Header[1])."</tr>\r\n";
foreach($room_bookings AS $aRoomsBookings)
{
echo "<tr>";
$First = true;
foreach($aRoomsBookings AS $aRoomTimeSlot)
{
if ($First)
{
$First = false;
echo "<td>".$aRoomTimeSlot['roomname']."</td>";
}
echo "<td>".(($aRoomTimeSlot['start'] == '') ? '' : 'xxxx')."</td>";
}
echo "</tr>\r\n";
}
echo "<table>";
mysqli_close($link);
?>
</table>
</body>
</html>

Related

PHP "array query" / multiple queries

I have a mysql table where I like to perform a query on. My table looks as following:
date activity amount
-------- ------ --------
day 1 drink 0
day 1 eat 1
day 1 breath 1
day 2 drink 0
day 2 eat 0
day 2 breath 0
day 3 drink 1
day 3 breath 0
day 4 eat 1
etc
etc
etc
What i'd like to do is to see when eat is 1, and for the days that is the fact, i'd like to display all activities for those days
//What I was doing right now is:
$activityarray = array();
$result = mysql_query("SELECT * FROM table WHERE activity='eat' AND amount='1'");
$row = mysql_fetch_assoc($result);
//this returns all rows where activity=eat and amount=1
do{
//perform for each result row a new query; look for the 'date'=$row[date] from the first query and show all activities that have been done that day (activity=1)
$result2 = mysql_query("SELECT * FROM table WHERE date='".$row[date]."'");
$row2 = mysql_fetch_assoc($result2);
do{
array_push($activityarray,$row2['activity']);
}while($row2 = mysql_fetch_assoc($result2));
}while($row = mysql_fetch_assoc($result));
print_r($activityarray);
Since there are thousands of days and dozens of activities per day, this seems not to be the most efficient method to me. Is there a way I can do this more efficient with one query? (So: check all activities for the days that eat=1).
Hope anyone could me me out!
Use a self-join:
SELECT t1.*
FROM table AS t1
JOIN table AS t2 ON t1.date = t2.date
WHERE t2.activity = 'eat' AND t2.amount = 1
My suggestion, especially if you have join size restrictions:
select *
from table as t1
where exists (
select 1
from table as t2
where t2.date = t1.date
and t2.activity = 'eat'
and t2.amount = 1
)

PHP/SQL - Add values together if ID is the same in foreach()

I am trying to show statistics for goals scored by players, however sometimes the same player is added to the database with the same playerID, when a player is added twice how can I add the values together to show it as a total, rather than echo the player twice.
db structure example:
playerID | Goals | Season | leagueID
1 5 1 1
2 1 1 1
1 2 1 2
5 3 1 1
1 3 2 2
2 2 2 1
php:
$query = $db->query('SELECT * FROM playerstats ORDER BY goals DESC LIMIT 30');
$num = $query->num_rows;
if($num > 0) {
foreach($query as $row) {
$playerID = $row['playerID'];
$goals = $row['goals'];
echo '
<tr>
<td>'.$playerID.'</td>
<td>'.$goals.'</td>
</tr>
';
}
}
This would show playerID 1, 3 seperate times.
How can I make it show playerID 1 just once with all the goals added together (10)
I have tried changing the query to: SELECT DISTINCT * FROM playerstats ORDER BY goals DESC LIMIT 30 but this made no difference.
Group BY will help you:
<?php
$query = $db->query('SELECT SUM(p.goals) as total_goals,
p.playerID, p.leagueID, p.Season
FROM playerstats as p
GROUP BY p.playerID, p.leagueID, p.Season
ORDER BY total_goals DESC LIMIT 30');
$num = $query->num_rows;
if($num > 0) {
foreach($query as $row) {
echo '
<tr>
<td>'.$row['playerID'].'</td>
<td>'.$row['total_goals'].'</td>
</tr>
';
}
}
Please note, that my query will group also by season and leagues, if you want total goals throughs seasons and leagues, your group by will be:
GROUP BY p.playerID
If you want only the playerID and the sum of the goals not mattering the Season or the leagueID, change your query to:
SELECT DISTINCT playerID AS player,
(SELECT SUM(goals) FROM playerstats WHERE playerID = player) AS totalGoals
FROM playerstats
Well you would group results in array then loop over it. Or sort at SQL level.
Something like this might work:
$playerStats = array();
foreach($query as $row)
{
if(array_key_exists($row['playerID'], $playerStats))
$playerStats[$row['playerID']] += $row['goals'];
else
$playerStats[$row['playerID']] = $row['goals'];
}
// Then loop over playerStats
foreach($playerStats as $playerID => $playerGoals)
}
echo $playerID;
echo $playerGoals;
{

Checking users options from default

I have table:
user_id | song_id| points
--------|----------------
2 | 1 | 0
2 | 2 | 1
2 | 3 | 2
2 | 4 | 3
2 | 5 | 4
And I need to check if the user have changed the points value.
Therefore it should be something like:
while ($row = mysql_fetch_array($query)) {
$userID = $row['user_id'];
$songID = $row['song_id'];
$points = $row['points'];
if($songID-$points==1){
echo $userID."<br>";
}
But this will print out every occasion of userID where the song-id - points=1.
I need to print out only these user_id's that have all the values =1 and the username must echo'd only once.
EDIT:
SELECT DISTINCT user_id WHERE (song_id - points) = 1
This is half way there. This echo's user_ids' where the song_id - points = 1, but if the user is reordered (i use jQuery sortable) the list, then there can be some rows that is "song_id - points = 1".
My script must echo only these user_id-s, where users every song_id - points = 1, not only one
SELECT DISTINCT user_id FROM table WHERE (song_id - points) = 1
After edit:
SELECT table.user_id
FROM table
LEFT JOIN (
SELECT user_id, COUNT(*) AS C FROM table) AS T2
ON table.user_id = T2.user_id
WHERE (table.song_id - table.points) = 1
GROUP BY table.user_id
HAVING COUNT(*) = T2.C
You can first filter the users which has modified point values:
SELECT DISTINCT user_id FROM table
WHERE (song_id - points) != 1
Then you can use fetch the users which doesn't fit the above condition:
SELECT DISTINCT user_id FROM table
WHERE user_id NOT IN (
SELECT DISTINCT user_id FROM table
WHERE (song_id - points) != 1
)
According to your last edit this last SQL statement might work.
You can check a working example.
Here is what you're looking for:
select user_id from (
select user_id, if(song_id - points = 1, 0, 1) flag from t
) as S
group by user_id
having sum(flag) = 0
And here is a working example.
In case I didn't understand the requirements this shows all users who don't even have one row in which song_id - points != 1, i.e, all users who have all rows that match song_id - points = 1
Or maybe, if you prefer a different approach that might be more efficient:
select distinct t1.user_id from t t1
where not exists (
select * from t t2
where t2.song_id - t2.points != 1 and t1.user_id = t2.user_id
)
Here is the working example.
Not sure I understand the why of the situation, but a simple control-break structure will achieve the desired result ...
$old_id = '';
$good = false;
while($row = mysql_fetch_array($query)){
//check to see if we have a new user ...
if($row['user_id'] != $old_id){
//check to see if all values were == 1
if($good){
echo $old_id . '<br />';
}
//re-initialize variables
$good = true;
$old_id = $row['user_id'];
}
//if value != 1, we won't print the user ...
if($row['song_id'] - $row['points'] != 1){
$good = false;
}
}
//final end-of-loop condition ...
if($good){
echo $old_id . '<br />';
}
OK, here's a query that's a lot more simple than the join above:
SELECT user_id, sum(song_id) as song_total, sum(points) as point_total, count(*) AS cnt FROM table GROUP BY user_id
If the difference between song_id and points is 1 for every song, then the difference between the totals will equal the number of rows for that user ... so using this query:
while($row = mysql_fetch_array($query)){
if($row['cnt'] == ($row['song_total'] - $row['point_total'])){
echo $row['user_id'] . '<br />';
}
}

How do I join two mysql statments and get the count for big data

Currently my code is like this:
<?php
$qall = $db->query("SELECT * FROM location_code
WHERE
StateCode='".$secureStateCode."'");
while($fall = $db->fetch($qall)) {
?>
<tr>
<th><?php echo $fall['StateCode']; ?></th>
<td><?php echo $fall['StateName']; ?></td>
<td>
<?php
$query = $db->query("SELECT COUNT(*) AS `male_count`
FROM `all_users`
WHERE `Sex`='M'
AND
`StateCode`='{$fall['StateCode']}'");
$data = $db->fetch($query);
echo $data['male_count'];
?>
</td>
<td>
<?php
$query = $db->query("SELECT COUNT(*) AS `female_count`
FROM `all_users`
WHERE `Sex`='F'
AND
`StateCode`='{$fall['StateCode']}'");
$data = $db->fetch($query);
echo $data['female_count'];
?>
</td>
<td>Total male_count + female_count</td>
</tr>
<?php } ?>
How do I combine these queries and get them loading faster for the total of male & female. Currently I have about 500k users.
$db->query("
SELECT
`Sex`,
COUNT(*) AS count,
FROM
`all_users`
WHERE
`StateCode` = '{$fall['StateCode']}'
GROUP BY
`Sex` WITH ROLLUP
");
Should return three rows, like so:
----------------
+ Sex + count +
----------------
+ F + 12345 +
+ M + 54321 +
+ null + 66666 +
----------------
You should be able to get the rest from there =)
You change this from you original query
SELECT COUNT(*) AS `male_count` FROM `all_users` WHERE `Sex`='M'
To this
SELECT `Sex`, COUNT(*) AS `Amount` FROM `all_users` GROUP BY `Sex`
This is how I would do it in SQL, so I'm not sure if it works in MySQL. You would have to change the way your php handled the table as well assuming the results would be like:
Sex | Amount
-----------------
M | 200000
F | 300000
Let the query do the work for you ... don't let a bunch of chatter requests do for you.
select
PreQuery.StateCode,
PreQuery.TotalRecords,
PreQuery.Male_Count,
PreQuery.Female_Count,
LC.*
from
( select
au.stateCode,
count(*) as TotalRecords,
sum( if( su.Sex = 'M', 1, 0 )) as Male_Count,
sum( if( su.Sex = 'F', 1, 0 )) as Female_Count
from
All_users au
where
au.StateCode = $secureStateCode
group by
au.StateCode ) PreQuery
join Location_Code LC
on PreQuery.StateCode = LC.StateCode

SQL Multiple Result question

Can I use a single SQL statement to return three separate results I can display through PHP? I'm looking to formulate three different "total" counts on a single table with three different conditions.
Eg something like....
$resultGetTotals = SELECT COUNT(Total1) FROM table_xyz WHERE Status = X AS Total1
SELECT COUNT(Total2) FROM table_xyz WHERE Status = X AND Person = Y AS Total2
SELECT COUNT(Total3) FROM table_xyz WHERE Status = Y AND Person = X AS Total3
while ($rGetTotals = mysql_fetch_array($resultGetTotals)){
$Total1 = $rGetTotals["Total1"]
$Total2 = $rGetTotals["Total2"]
$Total2 = $rGetTotals["Total2"];
}
Total One is: <?php print $Total1; ?><br>
Total Two is: <?php print $Total2; ?><br>
Total Three is: <?php print $Total3; ?><br>
Any help greatly appreciated :)
SQL:
SELECT SUM(CASE WHEN t.status = X THEN 1 ELSE 0 END) AS total1,
SUM(CASE WHEN t.status = X AND t.person = Y THEN 1 ELSE 0 END) AS total2,
SUM(CASE WHEN t.status = Y AND t.person = X THEN 1 ELSE 0 END) AS total3
FROM TABLE_XYZ t
PHPified:
$result = mysql_query("SELECT SUM(CASE WHEN t.status = X THEN 1 ELSE 0 END) AS total1,
SUM(CASE WHEN t.status = X AND t.person = Y THEN 1 ELSE 0 END) AS total2,
SUM(CASE WHEN t.status = Y AND t.person = X THEN 1 ELSE 0 END) AS total3
FROM TABLE_XYZ t");
while ($row = mysql_fetch_array($result)) {
echo "Total One is: $row['total1']<br>"
echo "Total Two is: $row['total2']<br>"
echo "Total Three is: $row['total3']<br>"
}
mysql_free_result($result);
Assuming you want the number of rows for each user (and not the number of non-null values in three different columns), and then for all users, and further assuming that there are only Person X and Y in the table, use:
SELECT Person, COUNT(*) FROM table_xyz GROUP BY Person
Retrieve the two totals (for person X and person Y) and add them together to get the grand total.

Categories