I am trying to query a table that is setup with id, startDateTime, endDateTime. Let's say row 1 looks like this:
id startDateTime endDateTime
100 2/9/2012 20:55 3/21/2012 10:43
I need to query the above such that I get a distinct count of all the days in the above range.
My expected result would be in the above 42 as there are 42 unique calendar days from 2/9 through 3/21. Datediff because it looks at the time piece gives me 41 days. I have tried various iterations of datediff and timediff trying to get this to work but can't find anything that works in all scenarios. Any suggestions as to how this can be done in SQL?
I started with a query as shown below:
SELECT ConditionStatus.ID,
SUM((DATEDIFF(ConditionStatus.endDate,ConditionStatus.startDate))) AS Duration
WHERE ID = 100
My query returns a Duration of 41 which is technically accurate but I need to condition such that every date in the range of dates gets a count of 1
I am trying to mimic some logic we use on our datawarehouse where we persist a count of 1 for each date for which there was activity.
Thanks,
Bob
The basic answer is that you can use DATEDIFF() and add 1 because you want to include the current day.
For example:
mysql> select datediff(current_date(),current_date()) + 1;
+---------------------------------------------+
| datediff(current_date(),current_date()) + 1 |
+---------------------------------------------+
| 1 |
+---------------------------------------------+
1 row in set (0.00 sec)
Expanding on your original example, you can convert the strings to datetimes, then discard the time component, then calculate the inclusive date count with a query like this:
mysql> SELECT ABS(DATEDIFF(DATE(STR_TO_DATE('2/9/2012 20:55','%m/%d/%Y %H:%i')),
-> DATE(STR_TO_DATE('3/21/2012 10:43','%m/%d/%Y %H:%i')))) + 1 as days_in_range;
+---------------+
| days_in_range |
+---------------+
| 42 |
+---------------+
1 row in set (0.00 sec)
mysql> SELECT ABS(DATEDIFF(DATE(STR_TO_DATE('3/21/2012 10:43','%m/%d/%Y %H:%i')),
-> DATE(STR_TO_DATE('2/9/2012 20:55','%m/%d/%Y %H:%i')))) + 1 as days_in_range;
+---------------+
| days_in_range |
+---------------+
| 42 |
+---------------+
1 row in set (0.00 sec)
See this answer - How do I select the number of distinct days in a date range?
Take a look before you use #Ike's answer. If you add +1, you will get one too many in instances where the time value is 00:00:00.
select datediff(days, '2/9/2012 20:55', '3/21/2012 10:43') returns 41
select datediff(days, '2/9/2012 20:55', '3/21/2012 10:43') + 1 returns 42
This is where that breaks -
select datediff(days, '2/9/2012 20:55', '3/21/2012 00:00:00') + 1 returns 42
That's the wrong answer. It should not include the last day.
Here's the workaround -
datediff(days, '2/9/2012 20:55', dateadd(seconds, -1, '3/21/2012 00:00:00') + 1
Related
LEFT or DATE_FORMAT, which is faster to re-format date in SELECT query in mysql?
I'll show an example of this problem.
Info of PERSON table
Column name
Type
NAME
VARCHAR(20)
YEAR
DATETIME
PERSON
NAME
YEAR
Travis
2020-01-01
Sam
2021-01-01
If execute 'SELECT YEAR FROM PERSON' query, can see below result.
YEAR
2020-01-01 00:00:00
2021-01-01 00:00:00
But I want result like below.
YEAR
2020-01-01
2021-01-01
So, I wanted use one of below queries.
SELECT LEFT(YEAR,10) FROM PERSON
SELECT DATE_FORMAT(YEAR, '%Y-%m-%d')
However, I wonder what query perform better.
Please, help me..
Technically, LEFT() is nearly four times faster, based on this test on my M1 Macbook. Your result might vary.
mysql> select benchmark(100000000, left(year, 10)) from person;
+--------------------------------------+
| benchmark(100000000, left(year, 10)) |
+--------------------------------------+
| 0 |
+--------------------------------------+
1 row in set (1.75 sec)
mysql> select benchmark(100000000, date_format(year, '%Y-%m-%d')) from person;
+-----------------------------------------------------+
| benchmark(100000000, date_format(year, '%Y-%m-%d')) |
+-----------------------------------------------------+
| 0 |
+-----------------------------------------------------+
1 row in set (6.81 sec)
But given that I had to execute both expressions 100 million times to observe a significant difference, both of them are so fast that I wouldn't worry about it. It's likely that other parts of the query will be of far greater influence on performance.
Worrying about which of these two functions has better performance is like worrying if it's better to use one finger or two fingers to lift a 100kg barbell.
How to get the current time in millisecond in MySQL.
So far what I've got is UNIX_TIMESTAMP().
But it returns the current time in seconds.
But I want the current time in milliseconds in UTC since '1970-01-01 00:00:00' in MySQL.
Any suggestion?
Looking at the documentation, it sounds like you want
NOW(3)
... where the value 3 is used to specify that you want 3 digits of subsecond precision, i.e. milliseconds. (Unfortunately none of the examples in the docs show that being used, so it's relatively tricky for me to check this...)
To get that as a "milliseconds since the Unix epoch" value, you'd probably want to use:
UNIX_TIMESTAMP(NOW(3)) * 1000
Thi is my answer;
mysql> Select curtime(4);
+------------+
| curtime(4) |
+------------+
| 13:27:20 |
+------------+
1 row in set (0.00 sec)
Or can also make this:
mysql> select conv(
-> concat(
-> substring(uid,16,3),
-> substring(uid,10,4),
-> substring(uid,1,8))
-> ,16,10)
-> div 10000
-> - (141427 * 24 * 60 * 60 * 1000) as current_mills
-> from (select uuid() uid) as alias;
+---------------+
| current_mills |
+---------------+
| 1427995791797 |
+---------------+
1 row in set (0.00 sec)
Here's my MySQL query:
SELECT YEARWEEK(paid) AS yweek,
STR_TO_DATE(YEARWEEK(paid), '%X%V') AS date,
COUNT(*) AS cnt
FROM members
WHERE YEARWEEK(paid) >= YEARWEEK(curdate()) - 52
GROUP BY yweek
Here is the result:
yweek date cnt
201429 0000-00-00 201
201430 0000-00-00 435
201431 0000-00-00 333
201432 0000-00-00 470
201433 0000-00-00 534
The yweek column and cnt column are fine, but the date column is always 0000-00-00. The paid column in the members table is of the format (PHP) date("Y-m-d H:i:s"), is of the column type TIMESTAMP, and here's an example: 2014-06-26 00:32:02.
I have tried replacing YEARWEEK(paid) with CAST(YEARWEEK(paid) AS CHAR(7)), but that changes nothing.
Does the fact that I'm using a TIMESTAMP cause STR_TO_DATE() to give all zeros? I want to have the first date of the week along with cnt, the number of registrations in that week.
Problem is: you cannot get a date from a yearweek: there's 7 options, which one do you want?
mysql> SELECT STR_TO_DATE('201429', '%X%V');
+-------------------------------+
| STR_TO_DATE('201429', '%X%V') |
+-------------------------------+
| 0000-00-00 |
+-------------------------------+
1 row in set (0.00 sec)
If we add a 'day of the week' (%w) to it, it magically begins to worK:
mysql> SELECT STR_TO_DATE('2014290', '%X%V%w');
+----------------------------------+
| STR_TO_DATE('2014290', '%X%V%w') |
+----------------------------------+
| 2014-07-20 |
+----------------------------------+
1 row in set (0.00 sec)
But: this means you have to choose the day of the week you want statically, because the original date is no longer in a yearweek.
Of course, in this case, you might as well have done this:
SELECT
YEARWEEK(paid) AS yweek,
DATE(paid) AS date,
COUNT(*) AS cnt
....
... but I assumed this was just an illustration of the problem getting a date of a yearweek string. If not, then this second solution will just work for you.
Table field structure:
id fdate tdate name
1 2012-07-07 2012-07-30
2 2012-08-07 2012-09-30
3 2012-07-17 2012-08-30
Here
fdate--->one of the field in table
tdate--->another field in table
I Will pass Two values like 2012-07-07 and 2012-09-30
And I need the output From the above Range:
You Have to Check the condition like the following fdate between2012-07-07and2012-09-30and tdate between2012-07-07and2012-09-30 like that
Expected Output:
month Days
07 43
08 53
09 30
Edit: Based on the authors comments the question is - How do I count all the days and show a total grouped by month when passing it a date range and comparing it to the data in my table.
I know that this doesn't give you the exact result that you want, but I think it will help you in the right direction at the very least:
mysql> create table dateTest (id int(2), fdate date, tdate date);
Query OK, 0 rows affected (0.04 sec)
mysql> insert into dateTest values(1, '2012-07-07', '2012-07-30');
Query OK, 1 row affected (0.00 sec)
mysql> insert into dateTest values(1, '2012-08-07', '2012-09-30');
Query OK, 1 row affected (0.00 sec)
mysql> insert into dateTest values(1, '2012-07-17', '2012-08-30');
Query OK, 1 row affected (0.00 sec)
mysql> select month(tdate) as month, datediff(tdate, fdate) as tally from dateTest group by month(fdate), month(tdate);
+-------+-------+
| month | tally |
+-------+-------+
| 7 | 23 |
| 8 | 44 |
| 9 | 54 |
+-------+-------+
3 rows in set (0.00 sec)
As you can see, it is skipping the middle month as I am grouping by fdate, but it is a step in the right direction for you.
Have a look at the TIMESTAMPDIFF() function in MySQL.
What this allows you to do is pass in two TIMESTAMP or DATETIME values (or even DATE as MySQL will auto-convert) as well as the unit of time you want to base your difference on.
You can specify MONTH as the unit in the first parameter:
mysql>SELECT TIMESTAMPDIFF(MONTH, '2012-05-05', '2012-06-04')
-- Outputs: 1
mysql> SELECT TIMESTAMPDIFF(YEAR,'2002-05-01','2001-01-01');
-> -1
mysql> SELECT TIMESTAMPDIFF(MINUTE,'2003-02-01','2003-05-01 12:05:55');
-> 128885
Your question is not clear though. But I have this for you.
You need to fetch your data from MySQL table using php. Then you may calculate date difference there.
You may refer to this stackoverflow question How to calculate the difference between two dates using PHP? and the official php documentation about date_diff at http://php.net/manual/en/function.date-diff.php
You can use the between clause in my sql:
select * from tbl where datetime between '2012-07-07' and '2012-09-30';
as an example
I want to include the time it takes to run a query as part of the output. Is this possible?
For example, this query:
mysql> SELECT count(*) AS NumberOfUsers FROM mdl_user;
+---------------+
| NumberOfUsers |
+---------------+
| 5741 |
+---------------+
1 row in set (0.16 sec)
I want to run it so that the "0.16 sec" value appears in a second column. Something like:
mysql> SELECT
count(*) AS NumberOfUsers
, QUERY_TIME() AS TimeToRunQuery
FROM mdl_user;
+---------------+----------------+
| NumberOfUsers | TimeToRunQuery |
+---------------+----------------+
| 5741 | 0.16 sec |
+---------------+----------------+
1 row in set (0.16 sec)
Nope, sorry. If you're interested just for informational purposes, you can have your script simply time the query by recording the time when the query is sent and subtracting that from the time when the query completes.
In PHP, it'd look something like this:
$start_time = microtime();
execute_query();
$end_time = microtime() - $start_time; // execution time in microseconds