Select rows that fall between two times - php

I have a field that is a a DATETIME field.
How do I select rows that fall between between 12:00 am and 8:30 am?
when I type in this query:
$query = "select * from table where TIME(changetime) between '12:00:00 and '08:30:00'";
it gives me zero hits.
The changetime field has the date like this: 2015-07-14 10:57:57

12:00:00 is 12 PM (noon), not 12 AM (midnight). You need to use
WHERE TIME(changetime) BETWEEN '00:00:00' AND '08:30:00'

1) you don't need TIME(changetime), it could probably worsen your search-time because mysql will need to apply a function instead of using index.
use just changetime.
2) where changetime between '2015-07-14 10:57:57' and '2015-07-14 12:57:57'
http://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#operator_between
3) you need to use right range - in your example END_DATE is BEFORE START_DATE. So, between will return 0 (12:00:00 > 08:30:00)
4) look at #Barmar's comment, maybe you really want entries between some time in any date, not between the datetimes

Related

Fetch records from specific month and year in php and mysql

I have table where records are stored in 9/23/2014 this format of date.
I have searched a lot but all the result which i got there were in timestamp format(2013-12-27).
Can anybody help me, how retrieve data from specific month (say 'september' 2014)
Many thanks if help.
Table: events
id course description date start end
1 john test 9/23/2014 1:00pm 3:00pm
2 brad play 12/30/2014 5:00pm 8:00pm
My Code:
SELECT date FROM events WHERE MONTHNAME(date) = 'September' AND YEAR(date) = '2014'
You should use BETWEEN -
SELECT *
FROM `events`
WHERE `date` BETWEEN '2013-09-01' AND '2013-09-30';
Because your dates are stored as varchar's (you really should fix that) you'll have to convert the string to a date format and then search. The performance will be awful though -
WHERE STR_TO_DATE(`date`, '%m/%/d/%Y %h:%i:%s %p') BETWEEN STR_TO_DATE('2013-09-01', '%m/%/d/%Y') AND STR_TO_DATE('2013-09-30', '%m/%/d/%Y')
or
WHERE STR_TO_DATE(LEFT(`date`,LOCATE(' ',`date)),'%m/%d/%Y') BETWEEN '2013-09-01' AND '2013-09-30';
You can also use this method (although I prefer the first because of the control it offers) -
SELECT * FROM `table` WHERE YEAR(`date_column`) = 2013 AND MONTH(`date_column`) = 9;
EDIT: Updated to reflect the OP's table schema. You should always check reserved word information before naming your columns.
Simple try this:
$query = mysqli_query($connect,'SELECT columns FROM tablename WHERE MONTHNAME(datecolumnn) = 'September' AND YEAR(datecolumn) = '2014');
;)
You can try something like this:
SELECT * FROM my_table WHERE date_field BETWEEN DATE_FORMAT('%m/%d/%Y','2013-09-01') AND DATE_FORMAT('%m/%d/%Y','2013-09-30')
It should work.

mysql total working hours

id title start end
1 Doing Coding for this project. 2013-04-02 02:00:00 2013-04-02 04:00:00
2 Doing Coding for this project. 2013-04-02 04:00:00 2013-04-02 06:00:00
3 Doing Coding for this project. 2013-04-02 06:00:00 2013-04-02 06:30:00
I have above MySQL database table record. Now i want to get the total number of hours.
I am developing TimeSheet Management Application and we need to display total working hours with minutes and second of employee. (i.e 04:30:00 according to data i share)
what i have tried?
SELECT HOUR(TIMEDIFF(end,start)) AS 'totalHour' but works only for each row not on all records.
I have also tried TIMESTAMPDIFF.
Is this possible?
EDIT
From the answer i have received from people i have tried every single of them but everytime i just get 4 or 4.5000 but it should return 06:30:00.
The range of HOUR() function is 0 to 23 so it's not correct to use it for total hours in diff.
For single value you could use TIMESTAMPDIFF() like:
SELECT TIMESTAMPDIFF(HOUR, start, end) AS `totalHour` FROM ...
If you want to calculate it for whole project, you have to sum up all time differences and them print it formatted probably with funciton like TIME_FORMAT() which prints hour larger than 24:
If the time value contains an hour part that is greater than 23, the %H and %k hour format specifiers produce a value larger than the usual range of 0..23. The other hour format specifiers produce the hour value modulo 12.
So you can use:
SELECT TIME_FORMAT( SEC_TO_TIME( SUM( TIME_TO_SEC(end) - TIME_TO_SEC(start))), "%H")
AS `totalHour`
FROM ...
GROUP BY sort_of_project_id
If you need seconds/minutes too (as suggested in comment), use either:
time_to_sec( <left side of select>)/3600 which will return value like 4.84 hours
TIME_FORMAT( ..., "%H:%m:%s") which will display 4:38:24
Try this query
SELECT
id,
title,
TIME_FORMAT(SEC_TO_TIME(sum(TIME_TO_SEC(TIMEDIFF( end, start)))), "%h:%i") AS diff
FROM
tbl1
GROUP BY
title
According to the data that you have given answer should be 4:30. Pl cross check in you records.
FIDDLE
Try like this, it will give you the total no of hours:
For Example:
SELECT sum(time_to_sec(timediff(end, start ))/ 3600) AS 'totalHour' from test;
If you run this query for above table you given, it shows the output 4.5 hours.
Hope it will help you.
I already answered in other thread https://stackoverflow.com/questions/44560345/query-is-not-working/44567322#44567322
I just created a temporary table called dataimport
[Table Format][1]
and wrote a query as,
SELECT `EnNo`, work_dt,
SEC_TO_TIME(sum(TIMESTAMPDIFF(SECOND,login,logout))) as time_worked
from (
SELECT `EnNo`, date(`DateTime`) as work_dt, `DateTime` as login
, coalesce(
(SELECT MIN(`DateTime`)
FROM `dataimport` as b
WHERE a.EnNo = b.EnNo
and date(a.`DateTime`) = date(b.`DateTime`)
and b.`DateTime` >= a.`DateTime`
and b.`INOUT` = 'E'
), now()) AS logout
FROM `dataimport` AS a
WHERE a.`INOUT` = 'S'
) as t
GROUP BY `EnNo`, work_dt
Finally got the output as,
[Output][2]
Hope this is what you are lookin on.
[1]: https://i.stack.imgur.com/OEEMe.png
[2]: https://i.stack.imgur.com/g6ivm.png
Change your
SELECT HOUR(TIMEDIFF(end,start)) AS 'totalHour'
to
SELECT sum(TIMESTAMPDIFF(HOUR, end, start)) AS 'totalHour'
SELECT IF(DATE(datetime_end) = DATE(datetime_start), TIMEDIFF(datetime_end,datetime_start), IF(DATEDIFF(datetime_start,datetime_end) > 1, ADDTIME( TIME_FORMAT(CONCAT((DATEDIFF(datetime_start,datetime_end) - 1) * 8,':00:00'), "%H:%i:%s"), ADDTIME( TIMEDIFF(datetime_end,CONCAT(DATE(datetime_end),' 08:00:00')), TIMEDIFF(CONCAT(DATE(datetime_start),' 17:00:00'),datetime_start) ) ) , ADDTIME( TIMEDIFF(datetime_end,CONCAT(DATE(datetime_end),' 08:00:00')), TIMEDIFF(CONCAT(DATE(datetime_start),' 17:00:00'),datetime_start) ) ) ) AS total_working_hrs FROM table

Working out the amount of free dates in a given time period

I have a fun one for you. I have a database with the date columns free_from and free_until. What I need to find is the amount of days between now and 1 month today which are free. For example, if the current date was 2013/01/15 and the columns were as follows:
free_from | free_until
2013/01/12| 2013/01/17
2013/01/22| 2013/01/26
2013/01/29| 2013/02/04
2013/02/09| 2013/02/11
2013/02/14| 2013/02/17
2013/02/19| 2013/02/30
The answer would be 16
as 2 + 4 + 6 + 2 + 2 + 0 = 16
The first row only starts counting at the 15th rather than the 12th
since the 15th is the current date.
The last row is discounted because none of the dates are within a
month of the current date.
The dates must be counted as it the free_from date is inclusive and
the free_until date is exclusive.
I'm assuming DATEDIFF() will be used somewhere along the line, but I can't, for the life of me, work this one out.
Thanks for your time!
Edit: This is going into PHP mysql_query so that might restrict you a little concerning what you can do with MYSQL.
SET #today = "2013-01-15";
SET #nextm = DATE_ADD(#today, INTERVAL 1 month);
SET #lastd = DATE_ADD(#nextm, INTERVAL 1 day);
SELECT
DATEDIFF(
IF(#lastd> free_until, free_until, #lastd),
IF(#today > free_from, #today, free_from)
)
FROM `test`
WHERE free_until >= #today AND free_from < #nextm
That should work. At least for your test data. But what day is 2013/02/30? :-)
Dont forget to change #today = CURDATE();
The best I can think of is something like:
WHERE free_until > CURDATE()
AND free_from < CURDATE() + INTERVAL '1' MONTH
That will get rid of any unnecessary rows. Then on the first row do in PHP:
date_diff(date(), free_until)
On the last row, do:
date_diff(free_from, strtotime(date("Y-m-d", strtotime($todayDate)) . "+1 month"))
Then on intermediate dates do:
date_diff(free_from, free_until)
Something to that effect, but this seems extremely clunky and convoluted...
From the top of my mind... first do a:
SELECT a.free_from AS a_from, a.free_until AS a_until, b.free_from AS b_from
FROM availability a
INNER JOIN availability b ON b.free_from > a.free_until
ORDER BY a_from, b_from
This probably will return a set of rows where for each row interval you have next i.e. greater intervals. The results are ordered strategically. You can then wrap the results in a partial group by:
SELECT * FROM (
SELECT a.free_from AS a_from, a.free_until AS a_until, b.free_from AS b_from
FROM availability a
INNER JOIN availability b ON b.free_from > a.free_until
ORDER BY a_from, b_from
) AS NextInterval
GROUP BY a_from, b_until
In the above query, add a DATE_DIFF clause (wrap it in SUM() if necessary):
DATE_DIFF(b_until, a_from)

how do I get month from date in mysql

I want to be able to fetch results from mysql with a statement like this:
SELECT *
FROM table
WHERE amount > 1000
But I want to fetch the result constrained to a certain a month and year (based on input from user)... I was trying like this:
SELECT *
FROM table
WHERE amount > 1000
AND dateStart = MONTH('$m')
...$m being a month but it gave error.
In that table, it actually have two dates: startDate and endDate but I am focusing on startDate. The input values would be month and year. How do I phrase the SQL statement that gets the results based on that month of that year?
You were close - got the comparison backwards (assuming startDate is a DATETIME or TIMESTAMP data type):
SELECT *
FROM table
WHERE amount > 1000
AND MONTH(dateStart) = {$m}
Caveats:
Mind that you are using mysql_escape_string or you risk SQL injection attacks.
Function calls on columns means that an index, if one exists, can not be used
Alternatives:
Because using functions on columns can't use indexes, a better approach would be to use BETWEEN and the STR_TO_DATE functions:
WHERE startdate BETWEEN STR_TO_DATE([start_date], [format])
AND STR_TO_DATE([end_date], [format])
See the documentation for formatting syntax.
Reference:
MONTH
YEAR
BETWEEN
STR_TO_DATE
Use the month() function.
select month(now());
Try this:
SELECT *
FROM table
WHERE amount > 1000 AND MONTH(dateStart) = MONTH('$m') AND YEAR(dateStart) = YEAR('$m')
E.g.
$date = sprintf("'%04d-%02d-01'", $year, $month);
$query = "
SELECT
x,y,dateStart
FROM
tablename
WHERE
AND amount > 1000
AND dateStart >= $date
AND dateStart < $date+Interval 1 month
";
mysql_query($query, ...
This will create a query like e.g.
WHERE
AND amount > 1000
AND dateStart >= '2010-01-01'
AND dateStart < '2010-01-01'+Interval 1 month
+ Interval 1 month is an alternative to date_add().
SELECT Date('2010-01-01'+Interval 1 month)-> 2010-02-01
SELECT Date('2010-12-01'+Interval 1 month)-> 2011-01-01
This way you always get the first day of the following month. The records you want must have a dateStart before that date but after/equal to the first day of the month (and year) you've passed to sprintf().
'2010-01-01'+Interval 1 month doesn't change between rows. MySQL will calculate the term only once and can utilize indices for the search.
Try this
SELECT *
FROM table
WHERE amount > 1000
AND MONTH(datestart)
GROUP BY EXTRACT(YEAR_MONTH FROM datestart)
Try this if(date field is text then convert this string to date):
SELECT * FROM `table_name` WHERE MONTH(STR_TO_DATE(date,'%d/%m/%Y'))='11'
//This will give month number MONTH(STR_TO_DATE(date,'%d/%m/%Y'))
//If its return 11 then its November
// Change date format with your date string format %d/%m/%Y
Works in: MySQL 5.7, MySQL 5.6, MySQL 5.5, MySQL 5.1, MySQL 5.0, MySQL 4.1, MySQL 4.0, MySQL 3.23
Day:
SELECT EXTRACT(DAY FROM "2017-06-15");
Month:
SELECT EXTRACT(MONTH FROM "2017-06-15");
Year:
SELECT EXTRACT(YEAR FROM "2017-06-15");

How to minimize the load in queries that need grouping with different invervals?

I'm looking for a best practice advice how to speed up queries and at the same time to minimize the overhead needed to invoke date/mktime functions. To trivialize the problem I'm dealing with the following table layout:
CREATE TABLE my_table(
id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT,
important_data INTEGER,
date INTEGER);
The user can choose to show 1) all entries between two dates:
SELECT * FROM my_table
WHERE date >= ? AND date <= ?
ORDER BY date DESC;
Output:
10-21-2009 12:12:12, 10002
10-21-2009 14:12:12, 15002
10-22-2009 14:05:01, 20030
10-23-2009 15:23:35, 300
....
I don't think there is much to improve in this case.
2) Summarize/group the output by day, week, month, year:
SELECT COUNT(*) AS count, SUM(important_data) AS important_data
FROM my_table
WHERE date >= ? AND date <= ?
ORDER BY date DESC;
Example output by month:
10-2009, 100002
11-2009, 200030
12-2009, 3000
01-2010, 0 /* <- very important to show empty dates, with no entries in the table! */
....
To accomplish option 2) I'm currently running a very costly for-loop with mktime/date like the following:
for(...){ /* example for group by day */
$span_from = (int)mktime(0, 0, 0, date("m", $time_min), date("d", $time_min)+$i, date("Y", $time_min));
$span_to = (int)mktime(0, 0, 0, date("m", $time_min), date("d", $time_min)+$i+1, date("Y", $time_min));
$query = "..";
$output = date("m-d-y", ..);
}
What are my ideas so far? Add additional/ redundant columns (INTEGER) for day (20091212), month (200912), week (200942) and year (2009). This way I can get rid of all the unnecessary queries in the for loop. However I'm still facing the problem to very fastly calculate all dates that doesn't have any equivalent in database. One way to simply move the problem could be to let MySQL do the job and simply use one big query (calculate all the dates/use MySQL date functions) with a left join (the data). Would it be wise to let MySQL take the extra load? Anyway I'm reluctant to use all these mktime/date in the for loop. Since I have complete control over the table layout and code even suggestions with major changes are welcome!
Update
Thanks to Greg I came up with the following SQL query. However it still bugs me to use 50 lines of sql statements - build up with php - that maybe could be done faster and more elegantly otherwise:
SELECT * FROM (
SELECT DATE_ADD('2009-01-30', INTERVAL 0 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 1 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 2 DAY) AS day UNION ALL
SELECT DATE_ADD('2009-01-30', INTERVAL 3 DAY) AS day UNION ALL
......
SELECT DATE_ADD('2009-01-30', INTERVAL 50 DAY) AS day ) AS dates
LEFT JOIN (
SELECT DATE_FORMAT(date, '%Y-%m-%d') AS date, SUM(data) AS data
FROM test
GROUP BY date
) AS results
ON DATE_FORMAT(dates.day, '%Y-%m-%d') = results.date;
You definitely shouldn't be doing a query inside a loop.
You can group like this:
SELECT COUNT(*) AS count, SUM(important_data) AS important_data, DATE_FORMAT('%Y-%m', date) AS month
FROM my_table
WHERE date BETWEEN ? AND ? -- This should be the min and max of the whole range
GROUP BY DATE_FORMAT('%Y-%m', date)
ORDER BY date DESC;
Then pull these into an array keyed by date and loop over your data range as you are doing (that loop should be pretty light on CPU).
Another idea is not to use string inside the query. Transform the string parameter to datetime, on mysql.
STR_TO_DATE(str,format)
http://dev.mysql.com/doc/refman/5.0/en/date-and-time-functions.html

Categories