LEFT vs. DATE_FORMAT in mysql - mysql

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.

Related

What is the unit of the difference of two timestamps in MySQL?

There are two columns (t0 and t1) whose types are timestamp (t0 = 2021-11-18 20:25:09 and t1 = 2021-11-18 20:36:41)
I want to find t1 - t0 (expecting ~11 minutes or ~ 700seconds), but the result is 1132.
I was wondering how - is done between two timestamps and what the unit is.
Use the TIMESTAMPDIFF function for that purpose
For your question:
mysql converts the string into a number and then subtracts, its deterministic but not the result you want
SELECT TIMESTAMPDIFF(MINUTE, '2021-11-18 20:25:09','2021-11-18 20:36:41')
| TIMESTAMPDIFF(MINUTE, '2021-11-18 20:25:09','2021-11-18 20:36:41') |
| -----------------------------------------------------------------: |
| 11 |
SELECT TIMESTAMPDIFF(SECOND, '2021-11-18 20:25:09','2021-11-18 20:36:41')
| TIMESTAMPDIFF(SECOND, '2021-11-18 20:25:09','2021-11-18 20:36:41') |
| -----------------------------------------------------------------: |
| 692 |
db<>fiddle here
> SELECT TIMEDIFF(t1, t2) FROM t;
+------------------+
| TIMEDIFF(t1, t2) |
+------------------+
| -00:11:32 |
+------------------+
1 row in set (0.000 sec)
Please see the example here
- does nothing useful for timestamps, except that the sign of the result will tell you which is greater (assuming month and day are not 0), which is easier tested with a comparison operator.
In general, if you cast a timestamp to a number, you get a number formed by putting the parts of the timestamp together. For instance:
select timestamp('2021-11-18 20:25:09.012345')+0
gives
20211118202509.012345
- effectively casts both operands to a number. So differences in days become differences in millions, differences in months become differences in hundreds of millions, and differences in years become differences in tens of billions. This doesn't provide any useful measure of the difference between two timestamps.

Mysql subtraction operator on timestamps [duplicate]

This question already has answers here:
What is the behavior for the minus operator between two datetimes in MySQL?
(2 answers)
Closed 1 year ago.
I wrote a query like
select endtime - begintime ....
and it looked like the difference in seconds. But it turns out that it is very odd number (both columns of type timestamp, no timezones mentioned).
select timestampdiff(seconds, begintime, endtime)
works.
But I am more than a little curious as to what the subtraction operator does! I could not find any documentation. It is certainly a booby trap for new users.
(And nobody really understand timezones. There is what is stored, vs what is displayed in different time zones, which drivers etc. muck with it, and lots and lots of false information and confusion. I don't know what With Timezone really means, but I only use the one timezone of the server, although my browser is in a different timezone so phpadmin might be lying to me.)
When used as a number, a timestamp like '2021-01-02 03:04:05' will be treated as 20210102030405. You can see this with e.g. select timestamp('2021-01-02 03:04:05')-0;. Subtracting two such "numbers" isn't going to be meaningful, except that the sign of the result will tell you which time was later.
This doesn't apply if you use the special INTERVAL syntax to adjust a timestamp by an interval, e.g. select '2021-01-02 03:04:05' - INTERVAL 1 WEEK;.
Here's a demo:
mysql> create table mytable (endtime datetime, begintime datetime);
Query OK, 0 rows affected (0.05 sec)
mysql> insert into mytable values (now(), '2021-05-01');
mysql> select endtime - begintime from mytable;
+---------------------+
| endtime - begintime |
+---------------------+
| 6011403 |
+---------------------+
What's up with this weird value? Well, when you put datetime values into an integer arithmetic expression, they values are converted to integers, but not in units of seconds. You can also force these values to be integers this way:
mysql> select endtime+0 as e, begintime+0 as b from mytable;
+----------------+----------------+
| e | b |
+----------------+----------------+
| 20210507011403 | 20210501000000 |
+----------------+----------------+
Here we see that the values are integers, but they are based on converting the datetime values to YYYYMMDDHHMMSS format.
Guess what the difference is?
mysql> select e-b from (select endtime+0 as e, begintime+0 as b from mytable) as t;
+---------+
| e-b |
+---------+
| 6011403 |
+---------+
But this is not the actual time difference, because there are not 100 minutes in an hour, 100 hours in a day, etc.
mysql> select timestampdiff(second, begintime, endtime) as timestampdiff from mytable;
+---------------+
| timestampdiff |
+---------------+
| 522843 |
+---------------+

MySQL datediff strange results

I am getting weird results for the datediff function.
It's zero for different and same timestamps?
select datediff('2015-04-25 20:37:45','2015-04-25 05:20:00');
+-------------------------------------------------------+
| datediff('2015-04-25 20:37:45','2015-04-25 05:20:00') |
+-------------------------------------------------------+
| 0 |
+-------------------------------------------------------+
select datediff('2015-04-25 20:37:45','2015-04-25 20:37:45');
+-------------------------------------------------------+
| datediff('2015-04-25 20:37:45','2015-04-25 20:37:45') |
+-------------------------------------------------------+
| 0 |
+-------------------------------------------------------+
datediff will do the calculation on the dates and find the difference in days,
however you can use timestampdiff for different difference like hour,min etc as
mysql> select timestampdiff(hour,'2015-04-25 05:20:00','2015-04-25 20:37:45') as hour;
+------+
| hour |
+------+
| 15 |
+------+
1 row in set (0.00 sec)
If you look at the MySQL Manual:
DATEDIFF
DATEDIFF() returns expr1 − expr2 expressed as a value in days from one date to the other. expr1 and expr2 are date or date-and-time expressions. Only the date parts of the values are used in the calculation
So what you are getting is correct.
If you are looking for time difference, I would suggest looking into TIMEDIFF or TIMESTAMPDIFF.
If you would like to get the difference in minutes, the best way would be TIMESTAMPDIFF.
Here is an example of how you could do it:
SELECT TIMESTAMPDIFF(MINUTE, '2015-04-25 20:37:45','2015-04-25 05:20:00');
+--------------------------------------------------------------------+
| TIMESTAMPDIFF(MINUTE, '2015-04-25 20:37:45','2015-04-25 05:20:00') |
+--------------------------------------------------------------------+
| -917 |
+--------------------------------------------------------------------+
you should use TIMEDIFF() function instead of DATEDIFF if you want to compare two timestamps with difference lower than day. For example:
select TIMEDIFF('2015-04-25 20:37:45','2015-04-25 05:20:00');
or for result in sec:
select TIME_TO_SEC(TIMEDIFF('2015-04-25 20:37:45','2015-04-25 05:20:00'));
For more details:
MySQL: how to get the difference between two timestamps in seconds
hope this helps :)

Query With STR_TO_DATE() Giving 000-00-00

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.

Return Unique Dates in Range of Days

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