Finding overlapping times from a select statement - php

Okay, so I have a table (timetable) in a database (calendar) which if formatted like so:
+----+--------+-----------+-----------+---------+
| id | name | day | startTime | endTime |
+----+--------+-----------+-----------+---------+
| 1 | George | Sunday | 12:00 | 14:00 |
| 2 | Dan | Monday | 13:30 | 15:30 |
| 3 | Jeff | Wednesday | 12:00 | 14:00 |
| 4 | Bill | Monday | 13:45 | 15:45 |
+----+--------+-----------+-----------+---------+
Then I have some PHP as follows:
<?php
$sql = "SELECT * FROM timetable WHERE id IN (1, 2, 3, 4)"
$result = $con->query($sql);
while ($row = mysqli_fetch_assoc($result)) {
$array2[] = $row;
}
echo json_encode($array2, JSON_PRETTY_PRINT);
?>
And that outputs the entire table, as an associated array in JSON format.
I want it to only output the two that clash. There will never be more than two that clash in the database due to the input method, so it only needs to check if there's one clash, and output the JSON for both rows.
I'm not sure where to start. Is it better to do it programatically via PHP, or is there a way to do with with mysql? I was thinking if it's done programatically, maybe two nested for loops and if statements for greater than or less than on the time fields? But seems messy, and I'm thinking there's likely a more clever end elegant solution that I can't think of.
Thank you for any help you can provide.

You can do it with JOIN in SQL like below:-
To find "any overlap", you compare the opposite ends of the timeframe with each other.
SELECT * FROM timetable a
JOIN timetable b
on a.starttime <= b.endtime
and a.endtime >= b.starttime
and a.name != b.name;

Related

How to show data based on date with column loop in one month in PHP MYSQL?

First, I have query like this:
SELECT
a.idpeg,
a.tanggal,
a.jam_masuk,
a.jam_pulang,
a.mode_absen
FROM
`tp_rekap_2018-01` a
WHERE
id_opd = '3'
AND periode = '2018-01'
And the result is:
+------+------------+-----------+------------+-----------+
|idpeg | tanggal | jam_masuk | jam_pulang | mode_absen|
+------+------------+-----------+------------+-----------+
|001 | 2018-01-01 | 07:01:01 | 14:01:01 | 1 |
|001 | 2018-01-02 | 08:01:01 | 15:01:01 | 1 |
|001 | 2018-01-03 | 09:01:01 | NULL | 1 |
|002 | 2018-01-01 | 10:01:01 | 16:01:01 | 1 |
|003 | 2018-01-01 | 11:01:01 | 17:01:01 | 1 |
|003 | 2018-01-02 | 12:01:01 | 18:01:01 | 1 |
+------+------------+-----------+------------+-----------+
my question is what I have to do when I want to show result of query with this format of table
Friend of mine suggest me to use the 'for' to loop the date/day and I was successfully generate day from day 1 to the last day of the month. But I can't get the loop script of date/day based on 'idpeg' from the left.
thx b4.
The correct way, i think is using PIVOTS. https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
There are many ways to do it. I can tell you what will be good solution in my opinion.
First of all, looks like you need some user system (make some user object in your PHP script and file or record in the database representing the user).
Then add the date records respectively to user id:
for (i = 0; i < idpeg.size; ++i)
user[a.idpeg[i]] = a.tanggal[i]
Then just use loop to print user data in columns as you did before.

Query MySQL count data & turn into JSON

My table contains a column of 'datetimes', with an id.
+----+---------------------+
| id | datetime |
+----+---------------------+
| 0 | 2016-09-02 12:13:13 |
| 1 | 2016-09-02 10:16:11 |
| 2 | 2016-09-05 11:03:23 |
| 3 | 2016-09-08 11:34:45 |
| 4 | 2016-09-08 09:23:06 |
| 5 | 2016-09-08 10:22:05 |
| .. | ... |
+----+---------------------+
There will be multiple instances of each date in the table. My aim is to gather the amount of times each date occurs. So for the table above:
2016-09-02 => 2
2016-09-05 => 1
2016-09-08 => 3
I then need to move the data into JSON format using PHP like so:
[{"date":"2016-09-02","count":"2"},
{"date":"2016-09-05","count":"1"},
{"date":"2016-09-08","count":"3"}]
The JSON format will be used by a d3.js script I have written to plot each date against the frequency each date occurs.
I have never dealt with this kind of query before so I really have no idea where to start, or how to use PHP to move into JSON format. Thank you to anyone that can help.
Use the following query:
SELECT DATE_FORMAT(datetime, '%Y-%m-%d') AS `date`,
COUNT(*) AS `count`
FROM yourTable
GROUP BY DATE_FORMAT(datetime, '%Y-%m-%d')
Then create the JSON in your PHP code:
$a = array();
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
$a[] = array('date' => "$row['date']", 'count' => "$row['count']");
}
$json = json_encode($a);
I think below SQL useful to you. please run and see
SELECT DATE_FORMAT(datetime, '%Y-%m-%d'),count(*)
FROM yourTable
GROUP BY 1
order by 1

Using PHP to GroupBy, looping through results and using count

I have search SO and found answers where people GROUP BY but haven't come across an answer where it displays the ability to GROUP BY (in this case date) and then get the user with the highest # of entries (in each of the date results).
I have my table set up as follows.
+----+------+-----------+-----------------+---------------------+
| id | name | reference | email | date |
+----+------+-----------+-----------------+---------------------+
| 1 | dan | 56453 | dan#example.com | 2015-05-01 09:00:01 |
| 2 | bob | 34564 | bob#example.com | 2015-05-01 09:21:03 |
| 3 | dan | 08948 | dan#example.com | 2015-05-01 09:30:08 |
| 4 | bob | 43775 | bob#example.com | 2015-05-02 09:01:43 |
| 5 | bob | 67210 | bob#example.com | 2015-05-02 09:04:13 |
| 6 | dan | 22195 | dan#example.com | 2015-05-02 09:09:11 |
+----+------+-----------+-----------------+---------------------+
Each day users log in and input a reference. Each day they could be logging many entries.
First, what I'm trying to do is GROUP BY the days and output the data.
So $day[0] which should equal "2015-05-01", should output those first 3 rows and who (and their count) has the highest number of entries for that day.
So output should be:
+----+------+-----------+-----------------+---------------------+
| Results of 2015-05-01 |
+----+------+-----------+-----------------+---------------------+
| 1 | dan | 56453 | dan#example.com | 2015-05-01 09:00:01 |
| 2 | bob | 34564 | bob#example.com | 2015-05-01 09:21:03 |
| 3 | dan | 08948 | dan#example.com | 2015-05-01 09:30:08 |
+----+------+-----------+-----------------+---------------------+
+----+------+-----------+-----------------+---------------------+
| Top user/s for 2015-05-01 |
+-----+-----+---------------------------------------------------+
| dan | 2 | |
+-----+-----+---------------------------------------------------+
So I need to be able to output the data for each day including the user with the most entries for that particular day.
My understanding is that I'd need to do something like this but can't quite grasp it.
$query = mysqli_query('SELECT * FROM mydata GROUP BY DATE(mydata.date as $date)');
$groupcount = 0;
while ($row = #mysqli_fetch_array($query))
{
$rowcount = 0;
$date[$groupcount] = $date;
$dayquery = mysqli_query('SELECT * FROM mydata WHERE date = $date)');
while ($entry = #mysqli_fetch_array($dayquery))
$data[] = array($row['$rowcount']['name'], $row['$rowcount']['reference'], $row['$rowcount']['email'], $row['$rowcount']['date']);
foreach ($data as $d) {
echo "Name: " . $d[0] . ", Reference: " . $d[1] . ", Email: " . $d[2] . ", Date: " . $d[3];
}
$rowcount++;
}
So something like that but also having another query that will output the person and the sum of the highest entries for that day. I just don't want to add another query as I think there would be a better way of structuring this to include COUNT in another.
Could potentially be multiple people with the same number of entries for the day so I'm trying to accommodate for that.
This should give you what you are looking for all in one query.
SELECT
max(m.id), -- since this column is unique you can ignore it if it's not important, or using min/max to get one of the values
max(m.reference), -- since this column appears to be unique you can ignore it if it's not important, or using min/max to get one of the values
m.name,
m.email,
cast(m.date as date) date,
count(*) count
FROM
mydata m
GROUP BY
m.name,
m.email,
cast(m.date as date)
ORDER BY
m.date DESC,
m.count DESC,
m.name ASC,
m.email ASC;

PHP MySQL SUM Between Month

I want to use BETWEEN in my PHP - MySQL.
Example I have table :
badge_id | balance_type | balance_amount | balance_month
110702 | aa | 250000 | January-2013
110702 | ab | 100000 | January-2013
110702 | aa | 100000 | February-2013
110702 | ab | 90000 | February-2013
110702 | aa | 100000 | March-2013
110702 | ab | 110000 | March-2013
Now I want to SUM just for Balance Month from January-2013 until February-2013.
SELECT balance_type AS balance_type, SUM(balance_amount) AS value_sum
FROM t_balance
WHERE badge_id = '110702' && balance_month BETWEEN 'August-2013'
and 'September-2013'
GROUP BY balance_type
But it will SUM all balance_month.
Any advice?
It's because you have a string column for balance_month. BETWEEN August-2013 and September-2013 is basically BETWEEN A AND S in the alphabet (don't know how to describe it better, lacking english skills here). J for January and F for February is between A and S, so MySQL counts those in. Convert your column to a date
WHERE ... AND STR_TO_DATE(balance_month, '%M-%Y') BETWEEN '2013-08-01'
and '2013-09-30'
But, if I were you I'd get rid of the column and use a real date column. Otherwise an index can not be used on it, when you always have to use a function like str_to_date() on it.
This will work...
SELECT balance_type AS balance_type, SUM(balance_amount) AS value_sum
FROM t_balance
WHERE badge_id = '110702' && STR_TO_DATE(balance_month,'%M-%Y') BETWEEN '2013-08-01'
and '2013-09-30'
GROUP BY balance_type
By an unfortunate twist of fate, all months are between August-2013 and September-2013 -- as you are probably comparing on strings not date.
On MySQL, proper date have the DATE (or one derivable) type and should be formatted as YYYY-MM-DD.

How do I perform an iterative calculation using a value from another table selected based on a YYYY-MM date and write it back to the first table?

Started learning PHP and MySQL yesterday and have managed to create two tables, insert rows and then display that data on a web page using various different groupings. Now I need to do a calculation based on data in the two tables and write the result back to one of the tables.
I'm trying to figure out how to perform an equation for a row with a date in table A using a range of values associated with a range of dates in table B. The two dates are in the format YYYY-MM-DD, but the days mostly do not match, so I need match on the month.
Here's the two tables I have:
Table A (user)
+----+----------+------------+-------------+
| id | username | start-date | bench-value |
+----+----------+------------+-------------+
| 1 | tim | 2010-03-04 | |
+----+----------+------------+-------------+
| 2 | jim | 2010-05-30 | |
+----+----------+------------+-------------+
| 3 | fred | 2010-06-12 | |
+----+----------+------------+-------------+
| 4 | sam | 2010-08-16 | |
+----+----------+------------+-------------+
| 5 | jane | 2010-10-21 | |
+----+----------+------------+-------------+
| 6 | ella | 2010-10-21 | |
+----+----------+------------+-------------+
| 7 | bob | 2011-01-24 | |
+----+----------+------------+-------------+
Table B (benchmark)
+----+------------+---------+
| id | start-date | value |
+----+------------+---------+
| 1 | 2010-01-31 | 1173.19 |
+----+------------+---------+
| 2 | 2010-02-28 | 1199.85 |
+----+------------+---------+
| 3 | 2010-03-31 | 1264.91 |
+----+------------+---------+
| 4 | 2010-04-30 | 1263.43 |
+----+------------+---------+
| 5 | 2010-05-31 | 1211.36 |
+----+------------+---------+
| 6 | 2010-06-30 | 1187.32 |
+----+------------+---------+
| 7 | 2010-07-31 | 1218.30 |
+----+------------+---------+
| 8 | 2010-08-31 | 1207.96 |
+----+------------+---------+
| 9 | 2010-09-30 | 1272.12 |
+----+------------+---------+
| 10 | 2010-10-31 | 1280.27 |
+----+------------+---------+
| 11 | 2010-11-30 | 1275.60 |
+----+------------+---------+
| 12 | 2010-12-31 | 1346.45 |
+----+------------+---------+
| 13 | 2011-01-31 | 1337.07 |
+----+------------+---------+
| 14 | 2011-02-28 | 1338.37 |
+----+------------+---------+
| 15 | 2011-03-31 | 1349.14 |
+----+------------+---------+
And here's an example of what I'm trying to achieve:
tim's current bench value today = the sum of: (first(benchmark.value)/latest(benchmark.value))for every month from the first to the latest month inclusive
First date = 2010-03 which is id 3 = 1264.91
Latest date = 2011-03 which is id 15 = 1349.14 (this is always the last row as I am trying to calculate on "today" and nothing in the future)
1/(first/latest) =1/(1264.91/1349.14) = 1.0666 [this is bench.id=3]
...now iterate...
1/(next/latest) =1/(1263.43/1349.14) = 1.0678 [bench.id=4]
1/(next/latest) =1/(1211.36/1349.14) = 1.1137 [bench.id=5]
1/(next/latest) =1/(1187.32/1349.14) = 1.1363 [bench.id=6]
1/(next/latest) =1/(1218.30/1349.14) = 1.1074 [bench.id=7]
1/(next/latest) =1/(1207.96/1349.14) = 1.1169 [bench.id=8]
1/(next/latest) =1/(1272.12/1349.14) = 1.0605 [bench.id=9]
1/(next/latest) =1/(1280.27/1349.14) = 1.0538 [bench.id=10]
1/(next/latest) =1/(1275.60/1349.14) = 1.0577 [bench.id=11]
1/(next/latest) =1/(1346.45/1349.14) = 1.0020 [bench.id=12]
1/(next/latest) =1/(1337.07/1349.14) = 1.0090 [bench.id=13]
1/(next/latest) =1/(1338.37/1349.14) = 1.0080 [bench.id=14]
...and finish up...
1/(current/latest) =1/(1349.14/1349.14) = 1.0000 [bench.id=15]
Total = 13.7997 = 1.0666 + 1.0678 + 1.1137 + 1.1363 + 1.1074 + 1.1169 + 1.0605 + 1.0538 + 1.0577 + 1.002 + 1.009 + 1.008 + 1
So I would then want to write that result back to Table A, giving me:
Table A (user)
+----+----------+------------+-------------+
| id | username | start-date | bench-value |
+----+----------+------------+-------------+
| 1 | tim | 2010-03-04 | 13.7997 |
+----+----------+------------+-------------+
As this is an iterative process it would be a much shorter calculation for a user like 'bob' who started in 2011-01.
I would also like to be able to do this every 4 months to produce termly stats so that someone like user tim would be calculated like this (the initial search to find the first date would need to take into account over a 4 month period):
1/(first/latest) = 2010-03 = 1/(1264.91/1349.14) = 1.0666
1/(next/latest) = 2010-07 = 1/(1218.30/1349.14) = 1.1074
1/(next/latest) = 2010-11 = 1/(1275.60/1349.14) = 1.0577
1/(current/latest) = 2011-03 = 1/(1349.14/1349.14) = 1.0000
Total = 1.0666 + 1.1074 + 1.0577 + 1 = 4.2317
That major issues I'm having are two fold:
1. how to use the user.start-date value for each user to pick the first(benchmark.value) based ont he year and the month (day is unimportant).
2. how to iteratively calculate the formula up to and including the latest value in the bench table - at the end of april, a new row with id=16 would be added and if this were run then the April value would become the last value used in the calculation.
As I'm learning SQL And PHP right now I'm not sure which parts of this process should be done in SQL and which in PHP.
Any and all help would be greatly appreciated as I'm determined to figure this out.
That major issues I'm having are two fold:
how to use the user.start-date value
for each user to pick the
first(benchmark.value) based on the
year and the month (day is
unimportant).
how to iteratively calculate the
formula up to and including the
latest value in the bench table - at
the end of april, a new row with
id=16 would be added and if this
were run then the April value would
become the last value used in the
calculation.
As I'm learning SQL And PHP right now I'm not sure which parts of this process should be done in SQL and which in PHP.
Any and all help would be greatly appreciated as I'm determined to figure this out.
Just for reference, I've been reading:
http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html
http://www.databasejournal.com/features/mssql/article.php/10894_2191631_3/Working-with-SQL-Server-DateTime-Variables.htm
There were more but it won't let me post the other links yet...
There's almost too much info out there, so some guided advice would be realy appreciated. Thanks again.
I wouldn't include the column bench-value in table A. This value will be constantly changing, so it would be better to create a View that would calculate the latest User bench-value or create a stored procedure that takes a User as a parameter and then returns the bench-value
There also needs to be a link/key between the two tables, right now there is no way to tell which user is related to which benchmark
Wow, what a well asked question. Sadly my reply maybe a lot shorter.
What I think you're looking for is:
bob's current bench value today = the
sum of:
first(benchmark.value)/latest(benchmark.value)
First date = 2011-01 which is id 13 =
1337.07 Latest date = 2011-03 which is id 15 = 1349.14
select username, start_date, tmp.value/tmp2.value as new_mark from tablea
join (select id,value from tableb having id=min(id) group by id) as tmp
on tablea.id=tmp.id
join (select id,value from tableb having id=max(id) group by id) as tmp2
on tablea.id=tmp2.id
That seems ugly but should work.

Categories