How to select rows based on datetime - mysql

I have to select some rows where the date is today or higher and I can select only the registers where the time is ten minutes before the current time. My doubt is on how to do that with 'datetime' type. Down below is the query:
SELECT
GROUP_CONCAT(timee.nome_time
ORDER BY timee.nome_time
SEPARATOR ' X ') AS nome_time,
partida.id,
DATE_FORMAT(partida.data_hora, '%d/%m/%Y %H:%i') AS data_hora,
partida.tb_cotacao_id
FROM
tb_partida AS partida,
tb_time AS timee,
tb_partida_time AS partidaTime
WHERE
(partida.id = tb_partida_id
&& timee.id = tb_time_id)
AND (partida.flag_ativo = 1
AND partida.flag_cancelado <> 1
AND partida.flag_finalizado <> 1)
AND partida.tb_campeonato_id = 11
GROUP BY partida.id
I'd really appreciate any help. Thanks in advance.

Use the TIME_TO_SEC(TIMEDIFF(now(),<datetime_field>) to get the time difference and convert it to seconds. For greater than 10 minutes it will be something like this
SELECT ... FROM .. WHERE TIME_TO_SEC( TIMEDIFF( now() , tb_time )) > 600 ...
EDIT
To get the rows that has time 10 minutes more than current time, just reverse the parameters inside the TIMEDIFF. ie.,
SELECT ... FROM .. WHERE TIME_TO_SEC( TIMEDIFF(tb_time, now() )) > 600 ...

Related

How I get difference between 2 times in words like "x hours y minutes z seconds" using mysql select query

I have two time column in a table name is start_time and end_time.
I need difference between these tile. e.g. start_time = 18:40:00 and end_time = 20:50:00.
output will be 2 hours 10 minutes.
Use TIMEDIFF function of MySQL
SELECT
TIMEDIFF(end_time,start_time) AS duration
FROM your_table;
TIMEDIFF() function
MySQL TIMEDIFF() returns the differences between two time or datetime expressions. It is to be noted that two expressions must be of same type.
Syntax :
TIMEDIFF(expr1,expr2)
Arguments
Name Description
expr1 A datetime value.
expr2 A datetime value.
EDIT:
If you want to get the duration in words (e.g. x hours y minutes z seconds):
SELECT
CONCAT
(
IF(HOUR(TIMEDIFF(end_time,start_time)) > 0, CONCAT(HOUR(TIMEDIFF(end_time,start_time)), ' hours'),''),
IF(MINUTE(TIMEDIFF(end_time,start_time)) > 0 , CONCAT(MINUTE(TIMEDIFF(end_time,start_time)),' minutes'),''),
IF(SECOND(TIMEDIFF(end_time,start_time)) > 0 , CONCAT(SECOND(TIMEDIFF(end_time,start_time)),' seconds'),'')
) AS duration
FROM your_table
Demonstration:
SET #end_time := '20:50:00';
SET #start_time := '18:40:00';
SELECT
CONCAT(
IF(HOUR(TIMEDIFF(#end_time,#start_time)) > 0, CONCAT(HOUR(TIMEDIFF(#end_time,#start_time)), ' hours '),''),
IF(MINUTE(TIMEDIFF(#end_time,#start_time)) > 0 , CONCAT(MINUTE(TIMEDIFF(#end_time,#start_time)),' minutes '),''),
IF(SECOND(TIMEDIFF(#end_time,#start_time)) > 0 , CONCAT(SECOND(TIMEDIFF(#end_time,#start_time)),' seconds'),'')
) AS duration;
output: 2 hours 10 minutes

MYSQL Add working days to date

I want to add 5 days to the provided date, but the calculation must skip weekends.
I already know how to add 5 days without skipping weekends:
SELECT DATE_ADD(`date_field`, INTERVAL 5 DAY) As FinalDate
FROM `table_name`;
Now I want the returned value to skip weekends.
Currently if date_field = 2016-07-22 the results will be 2016-07-27
But I want the results to be 2016-07-29
Try this:
SELECT DATE_ADD(
date_field,
INTERVAL 5 +
IF(
(WEEK(date_field) <> WEEK(DATE_ADD(date_field, INTERVAL 5 DAY)))
OR (WEEKDAY(DATE_ADD(date_field, INTERVAL 5 DAY)) IN (5, 6)),
2,
0)
DAY
) AS FinalDate
FROM `table_name`;
How it works:
Firstly, it will add 5 days on your date.
Secondly, when date_field and 5 days later are in two different weeks, it must be added additional 2 days.
Thirdly, when 5 days later is Sat or Sun, it must be added additional 2 days.
This can easily be done for an arbitrary amount of days with a recursive CTE:
WITH RECURSIVE a AS (
SELECT
CURRENT_DATE date, -- Start date
0 days
UNION
SELECT
-- Always increment the date
a.date + INTERVAL 1 DAY AS date,
-- Increment the work day count only if it's not a weekend day
a.days + (WEEKDAY(a.date + INTERVAL 1 DAY) < 5) AS days
FROM a
WHERE
-- Keep going until the week day count reaches 10
a.days < 10 -- Amount of days to add
)
SELECT MAX(date)
FROM a
In the example situation you would use a subquery:
SELECT
(
WITH RECURSIVE a AS (
SELECT
date_field date,
0 days
UNION
SELECT
a.date + INTERVAL 1 DAY AS date,
a.days + (WEEKDAY(a.date + INTERVAL 1 DAY) < 5) AS days
FROM a
WHERE a.days < 5
)
SELECT MAX(date)
FROM a
) AS final_date
FROM table_name
I did try your solution but faced a problem when using it with a larger interval (e.g 20 days). It works perfectly with little intervals though.
Example : for '2017-10-04' + 20 days, your algorithm return '2017-10-26'. It should be '2017-11-01' since we skip 4 weekends.
The numbers of days you add isn't calculated depending on the difference between the 2 week #, so the maximum days you can add is 2 and in my case, it should be 8 (4x2).
I modified your code to end up with this (I also add variables, much more convenient to modify)
SELECT
#ID:='2017-10-04' as initial_date, -- the initial date in the right format to manipulate (add x day)
#DTA:=20 as days_to_add, -- number of days to add
#DA:= DATE_ADD(#ID, INTERVAL #DTA DAY) as date_add,
#LASTDAY := WEEKDAY(#DA) as last_day, -- the day (Monday, Tuesday...) corresponding to the initial date + number of days to add
#WEEK1 := DATE_FORMAT(#ID, '%v') as initial_date_week, -- format the initial date to match week mode 3 (Monday 1-53)
#WEEK2 := DATE_FORMAT(#DA, '%v') as added_date_week_nbr, -- the week # of the initial_date + number of days to add
#WEEKDIFF := #WEEK2 - #WEEK1 as week_difference, -- the difference between week 2 and week 1
DATE_ADD(#ID,
INTERVAL #DTA +
if ( #WEEKDIFF > 0 or #LASTDAY in (5,6),
2,
0
) +
if (#WEEKDIFF > 1,
#WEEKDIFF*2,
0
) DAY
) AS FinalDate
The way I get my week numbers can seems weird but this is because I'm running this in France and my DB seems to be configured in a way that weeks are natively starting by Sunday, "%v" represent the 'mode 3' for weeks, you can check the MySQL documentation here for more details : https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html (ctrl + F > '%v')
I didn't implement the public holiday yet, but I'm thinking of adding X days in the calculation each times one of this day is in the period we're looking at.
According to my (few) tests, this should work. Let me know if not
try this out, should work nicely, basically loop through each of the days and check if they are saturday or sunday, ignore them.
https://social.technet.microsoft.com/wiki/contents/articles/30877.t-sql-extending-dateadd-function-to-skip-weekend-days.aspx
Plus hollydays 1 or 2
select GREATEST(WEEKDAY(NOW()) - 4, 0) 'hollydays'
My solution is to create a function that returns the calculated date, it will consider the consecutive weekends:
DELIMITER $$
CREATE FUNCTION `add_working_days_to_current_month`(ndays INT) RETURNS DATE
NO SQL
BEGIN
declare finalDate, startDate, originalFinalDate DATE;
declare weekNumberStartDate, weekNumberEndDate, weekDiff INT;
set startDate = DATE(CONCAT(YEAR(DATE_SUB(current_date(), INTERVAL 1 MONTH)),"-",MONTH(DATE_SUB(current_date(), INTERVAL 1 MONTH)),"-",DAY(LAST_DAY(DATE_SUB(current_date(), INTERVAL 1 MONTH)))));
set weekNumberStartDate = WEEK(startDate);
set finalDate = DATE_ADD(startDate, INTERVAL ndays DAY);
set originalFinalDate = finalDate;
set weekNumberEndDate = WEEK(finalDate);
IF(weekNumberEndDate != weekNumberStartDate) THEN
set weekDiff = (weekNumberEndDate - weekNumberStartDate) * 2;
set finalDate = DATE_ADD(finalDate, INTERVAL weekDiff DAY);
END IF;
set weekNumberStartDate = WEEK(originalFinalDate);
set weekNumberEndDate = WEEK(finalDate);
IF(weekNumberEndDate != weekNumberStartDate) THEN
set weekDiff = (weekNumberEndDate - weekNumberStartDate) * 2;
set finalDate = DATE_ADD(finalDate, INTERVAL weekDiff DAY);
END IF;
IF(WEEKDAY(finalDate) IN (5, 6)) THEN
set finalDate = DATE_ADD(finalDate, INTERVAL 2 DAY);
END IF;
return finalDate;
END$$
DELIMITER ;
Basically i'm using the same logic as the accepted answer but acumulating the weekends. So for each weekend i will add 2 days and at the end i will if the result date is on weekend i will add 2 more
WHERE datefield BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL 7 DAY
AND WEEKDAY(datefield) NOT IN (5,6);

Date difference in mysql based on 360 days

I working on a financial project where i need to calculate the difference of arrear days. If I use the method datediff() of mysql then it returns the result based on 365 days. I need the result based on 360 days. if use the following sql query
select datediff('20140908','20130908') from dual;
mysql returns the date difference 365. This is the actual date difference but in accounting/Financial calculation the difference is exactly one year (360 days). This is what I want. The result should be 360 instead 365.
Currently I want to use US standard.
to get the same result like Excel, I found the following code to use in MySQL:
select case
when (day(Startdate)>=30 or Startdate=last_day(Startdate) then
case
when(day(Enddate)>=30) then
30*(12*(year(Enddate)-year(Startdate))+month(Enddate)-month(Startdate))
else
30*(12*(year(Enddate)-year(Startdate))+month(Enddate)-month(Startdate))+days(Enddate)-30
end
else
30*(12*(year(Enddate)-year(Startdate))+month(Enddate)-month(Startdate))+days(Enddate)-days(Startdate)
end
Use
TO_DAYS(date2) - To_DAYS(date1)
It returns the number of days between date1 and date2. Then you can do with the result what you need.
sdate = from date
edate = to date
this calculate the days between the 2 date, taking into account that a month is 30 days, 1 year is 360 days, and checking if the date are at the end of the month, so e.g. from 1.1.2019 to 28.2.2019 = 60 days etc.
to be 1 month or 1 year, the edate should be a day before, so 1.1 - 31.1 = 30 days, 1.1 - 1.2 = 31 days
SELECT GREATEST(
0,
(YEAR(DATE_ADD(edate, INTERVAL 1 DAY)) - YEAR(sdate)) * 360 +
(MONTH(DATE_ADD(edate, INTERVAL 1 DAY)) - MONTH(sdate)) * 30 +
(
IF(DAYOFMONTH(DATE_ADD(edate, INTERVAL 1 DAY)) = DAYOFMONTH(LAST_DAY(DATE_ADD(edate, INTERVAL 1 DAY))), 30, DAYOFMONTH(DATE_ADD(edate, INTERVAL 1 DAY))) -
IF(DAYOFMONTH(sdate) = DAYOFMONTH(LAST_DAY(sdate)), 30, DAYOFMONTH(sdate))
)
Pretty late here, but posting my solution for future reference
CREATE FUNCTION `DAYS360_UDF`(sdate DATE, edate DATE)
RETURNS INTEGER
DETERMINISTIC
CONTAINS SQL
BEGIN
DECLARE sdate_360 INTEGER;
DECLARE edate_360 INTEGER;
SET sdate_360 = ( YEAR(sdate) * 360 ) + ( (MONTH(sdate)-1)*30 ) + DAY(sdate);
SET edate_360 = ( YEAR(edate) * 360 ) + ( (MONTH(edate)-1)*30 ) + DAY(edate);
RETURN edate_360 - sdate_360;
END
Usage -
select DAYS360_UDF('20130908', '20140908')

How can search a column by date format?

I'm trying to create a query according the day and month at the same time condition between 2 columns in a period of time like this:
Here is the demo
Here is the information:
CREATE TABLE clients
(date_birth date, [date_anniversary] date)
;
INSERT INTO clients
([date_birth], [date_anniversary])
VALUES
('1911-01-04',NULL ),('1921-01-05',NULL ),('1931-01-06',NULL ),('1941-01-07',NULL ),
('1951-01-08',NULL ),('1961-01-09',NULL ),('1971-01-10',NULL ),('1981-01-11',NULL ),
('1991-01-12',NULL ),(NULL, '1998-02-13'),(NULL, '1999-02-14'),(NULL, '2000-02-15'),
(NULL, '2001-02-16'),(NULL, '2002-02-17'),(NULL, '2003-02-18'),(NULL, '2004-02-19'),
(NULL, '2005-02-20'),(NULL, '2006-02-21');
Here is the condition:
since "04-01" until "13-02"
show all from clients where date_birth BETWEEN "04-01" AND "13-02" OR date_anniversary "04-01" AND "13-02"
This should be the output:
('1911-01-04',NULL ),
('1921-01-05',NULL ),
('1931-01-06',NULL ),
('1941-01-07',NULL ),
('1951-01-08',NULL ),
('1961-01-09',NULL ),
('1971-01-10',NULL ),
('1981-01-11',NULL ),
('1991-01-12',NULL ),
(NULL, '1998-02-13'),
I tried this but is just for month:
select date_birth from clients
where month(date_birth) BETWEEN '00' AND '01'
And also tried:
SET #date1 := 01-14;
SET #date2 := 02-20;
select date_birth from clients
where date_birth BETWEEN #date1 AND #date2
Please somebody can help me?
You can do so by using Mysql's month and day functions
SELECT date_birth ,date_anniversary
FROM clients
WHERE
(
MONTH(date_birth) >= 01 AND MONTH(date_birth) <= 01
AND DAY(date_birth) >= 01 AND DAY(date_birth) <= 31
)
OR
(
MONTH(date_anniversary) >= 01 AND MONTH(date_anniversary) <= 01
AND DAY(date_anniversary) >= 01 AND DAY(date_anniversary) <= 31
)
Fiddle Demo
using Mysql's date_format function just format your columns by day and month can compare with the provided range of same format,also provide your parameters as in this '%m-%d' format
select date_birth ,date_anniversary
from clients
where date_format(date_birth,'%m-%d') BETWEEN '01-01' AND '01-31'
or
date_format(date_anniversary,'%m-%d') BETWEEN '01-01' AND '01-31'
Fiddle demo 2
Storing values in variables
SET #start:='01-01';
SET #end:='01-31';
SELECT date_birth ,date_anniversary
FROM clients
WHERE DATE_FORMAT(date_birth,'%m-%d') BETWEEN #start AND #end
OR
DATE_FORMAT(date_anniversary,'%m-%d') BETWEEN #start AND #end
Fiddle demo 3
If you are using MySQL try this:
SELECT
date_birth
,date_anniversary
FROM clients
WHERE
DATE_FORMAT(date_birth, '%m-%d') BETWEEN DATE_FORMAT('1900-01-04', '%m-%d') AND DATE_FORMAT('1900-02-13', '%m-%d')
OR DATE_FORMAT(date_anniversary, '%m-%d') BETWEEN DATE_FORMAT('1900-01-04', '%m-%d') AND DATE_FORMAT('1900-02-13', '%m-%d')
If you are using MSSQL e posted into wrong subject try to google a DATE_FORMAT() function equivalent on it.

Getting last months data from the database

My query currently gets yesterdays data but I now want to get all of last months data. (E.g.from 1st to 31st)
$res = mysql_query("SELECT
FROM_UNIXTIME( enquiry_time ), `id` ,
`fullname` , `address1` , `citytown` ,
`postcode` , `telno` ,
`property_value` ,`total_secured_debt`
, `email` , `on_market` , `agent` ,
`reason` , `price_concession` ,
`asking_price` , `form_page` FROM
$table WHERE TO_DAYS(FROM_UNIXTIME( enquiry_time )) = (TO_DAYS(NOW())-1)
");
There is not a TO_MONTHS so im not sure where to start!
Try:
$res = mysql_query("
SELECT FROM_UNIXTIME(`enquiry_time`), `id`, `fullname`, `address1`,
`citytown`, `postcode`, `telno`, `property_value`, `total_secured_debt`,
`email`, `on_market`, `agent`, `reason`, `price_concession`,
`asking_price`, `form_page`
FROM $table
WHERE YEAR(FROM_UNIXTIME(`enquiry_time`)) = YEAR(CURDATE() - INTERVAL 1 MONTH)
AND MONTH(FROM_UNIXTIME(`enquiry_time`)) = MONTH(CURDATE() - INTERVAL 1 MONTH)
");
This would all work vastly better and faster if enquiry_time were a native DATE or DATETIME field, with an index, instead of a Unix timestamp.
Looking for function MONTH?
That will work (like your TO_DAYS does now), but remember you may be paying a hefty performance price if the table is large: MySQL can't use an index when the WHERE condition depends on a function rather than directly on the indexed column (use EXPLAIN to see the query plan and confirm that this is the case). Performance-wise, you're better off computing the lower and upper bound of the times you want to see (with functions and arithmetic on NOW()) and then using a straight BETWEEN in your WHERE. Again, use EXPLAIN to double check -- trying to second guess MySQL's query optimizer is a sterile exercise, it's much easier to check on what it plans to do;-).
Could you use something like the following? I think it will get you what you want.
FROM_UNIXTIME(enquiry_time)
BETWEEN date_format(NOW() - INTERVAL 1 MONTH, '%Y-%m-01')
AND last_day(NOW() - INTERVAL 1 MONTH)
Here's the reference.
While chaos's answer will work, if $table is indexed by enquiry_time,
then it will be faster to compare against that field directly than against a function of it.
That transforms his answer into the even uglier:
$res = mysql_query("
SELECT FROM_UNIXTIME(enquiry_time), id, fullname, address1,
citytown, postcode, telno, property_value, total_secured_debt,
email, on_market, agent, reason, price_concession, asking_price,
form_page
FROM $table
WHERE enquiry_time >= UNIX_TIMESTAMP(concat(year(curdate() - interval 1 month), '-', month(curdate() - interval 1 month), '-01'))
AND enquiry_time < UNIX_TIMESTAMP(concat(year(curdate()), '-', month(curdate()), '-01'))
");
i see you are using php so this might be better than wrestling with mysql functions:
$end_of_month = strtotime(date('Y-m-01 00:00:00'))-1;
$start_of_month = strtotime(date('Y-m-01 00:00:00',$end_of_month));
$res = mysql_query("SELECT
FROM_UNIXTIME( enquiry_time ), `id` ,
`fullname` , `address1` , `citytown` ,
`postcode` , `telno` ,
`property_value` ,`total_secured_debt`
, `email` , `on_market` , `agent` ,
`reason` , `price_concession` ,
`asking_price` , `form_page` FROM'
$table WHERE enquiry_time >= '".$start_of_month."' AND enquiry_time <= '".$end_of_month."'
");