Less value function MySQL - mysql

I'm learning basic MYSQL and I want to get only the less value in this query.
Select DATE_FORMAT(CURDATE(),'%Y') - DATE_FORMAT(HIRE_DATE,'%Y') from employees;
Is there any function that do that?
EDIT:
I found the solution by myself. If someone wants to see is like that:
select MIN(timestampdiff(year,HIRE_DATE,CURDATE())) as LessYearsWorking FROM employees;

For getting the least you have a least function
mysql> select least(year(curdate()),year('2014-01-01')) as l;
+------+
| l |
+------+
| 2014 |
+------+
1 row in set (0.04 sec)
And for getting the difference in years between 2 dates you can use timestampdiff
mysql> select timestampdiff(year,'2014-01-01',curdate()) as d ;
+------+
| d |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
Combining both of them and getting the difference and also the least value in the same query could be done as
select
timestampdiff(year,'2014-01-01',curdate()) as d,
least(year(curdate()),year('2014-01-01')) as l ;
So your query becomes
select
timestampdiff(year,HIRE_DATE,curdate()) as diff,
least(year(curdate()),year(HIRE_DATE)) as least_date
from employees

Related

Possible to emulate a recursive CTE?

I think the short answer to this is No, but is it possible to emulate a recursive CTE with something like a table function in a database that doesn't have support for a CTE? For example:
-- get weekday names -- 'Monday', 'Tuesday', ...
WITH cte_numbers(n, weekday) AS (
SELECT
0,
DATENAME(DW, 0)
UNION ALL
SELECT
n + 1,
DATENAME(DW, n + 1)
FROM
cte_numbers
WHERE n < 6
)
SELECT
weekday FROM cte_numbers;
For example could the above pattern be rewritten to run in Mysql5.7, or recursion cannot be emulated there?
None of the solutions is very efficient, and most of them involve writing more code than you should. It would be better to upgrade to MySQL 8.0.
SQL works best on sets, not on iteration. So the standard way to generate a series in a single query is to already have a set of rows in a temporary table, and apply some set-based operations to it.
For example:
SELECT 0 AS num UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5;
+-----+
| num |
+-----+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+-----+
With this as the basis, you can do date arithmetic and then extract the weekday names with DATE_FORMAT():
SELECT DATE_FORMAT(CURDATE() + INTERVAL num DAY, '%W') AS weekday
FROM (
SELECT 0 AS num UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5
) AS t;
+-----------+
| weekday |
+-----------+
| Friday |
| Saturday |
| Sunday |
| Monday |
| Tuesday |
| Wednesday |
+-----------+
You could also prepare a fixed base table of integers, fill it with as many as you need, and use it for different purposes.
SELECT DATE_FORMAT(CURDATE() + INTERVAL num DAY, '%W') AS weekday
FROM MySetOfIntegers
WHERE num BETWEEN 0 AND 5;
The suggestion of using an iterative approach would involve writing a lot more code. It will also mean N SQL queries, each generating a separate result set, so that's more code you have to write in your application to fetch all the result sets and append them together.
You could write a recursive stored procedure, but there's a risk of exceeding the thread stack space if you allow deep recursion. The default limit on stored procedure recursion is 0. That is, no recursion is allowed at all unless you set a finite limit. See https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_max_sp_recursion_depth
Here's an example of a recursive stored procedure:
DROP PROCEDURE IF EXISTS Weekdays;
DELIMITER //
CREATE PROCEDURE Weekdays(IN date DATE, IN num INT)
BEGIN
IF num >= 1 THEN
CALL Weekdays(date, num-1);
END IF;
SELECT DATE_FORMAT(date + INTERVAL num-1 DAY, '%W') AS weekday;
END//
DELIMITER ;
And calling it. Note it produces multiple result sets.
mysql> set max_sp_recursion_depth=6;
mysql> call Weekdays(CURDATE(), 6);
+----------+
| weekday |
+----------+
| Thursday |
+----------+
1 row in set (0.00 sec)
+---------+
| weekday |
+---------+
| Friday |
+---------+
1 row in set (0.00 sec)
+----------+
| weekday |
+----------+
| Saturday |
+----------+
1 row in set (0.00 sec)
+---------+
| weekday |
+---------+
| Sunday |
+---------+
1 row in set (0.00 sec)
+---------+
| weekday |
+---------+
| Monday |
+---------+
1 row in set (0.00 sec)
+---------+
| weekday |
+---------+
| Tuesday |
+---------+
1 row in set (0.00 sec)
+-----------+
| weekday |
+-----------+
| Wednesday |
+-----------+
1 row in set (0.00 sec)
I may have gotten the recursion off by one somewhere. This actually supports the point that it's not as easy as it sounds to implement a recursive routine.
Oh and you get an error — and no results — if you exceed the recursion limit.
mysql> call Weekdays(CURDATE(), 8);
ERROR 1456 (HY000): Recursive limit 6 (as set by the max_sp_recursion_depth variable) was exceeded for routine Weekdays

Mysql select Month names as numeric

I need to get Month number from event table using a mysql select query. here my EVENT table,
query
SELECT month(str_to_date(month,'%d')) AS m FROMevent``
but the result was
how can I convert my month column as numeric..
Use %M insted of %d
mysql> SELECT month(str_to_date('April','%M')) AS m;
+------+
| m |
+------+
| 4 |
+------+
1 row in set (0.05 sec)

substract timediff from time value

This is my table:
+----------+---------------------+
| estimate | timestamp |
+----------+---------------------+
| 05:00:00 | 2015-12-02 13:35:14 |
+----------+---------------------+
1 row in set (0.00 sec)
I am trying to implement a scheduled job to create extra automatic rows every hour to substract the time that has past from the estimated time.
I am able to start the scheduled job and use timediff to calculate the time that has passed since, but i am unable to substract the timediff from the estimated time.
I am guessing that mysql doesn't care much that i want the estimated time column to be stated as a period of time. instead, it just shows me a time without the date.
select timediff(now(),timestamp) from t1;
this gives me the time difference that i need:
+---------------------------+
| timediff(now(),timestamp) |
+---------------------------+
| 00:27:03 |
+---------------------------+
1 row in set (0.00 sec)
but when i do this:
select estimate-timediff(now(),timestamp) as timeleft from t1;
the result is:
+----------+
| timeleft |
+----------+
| 46568 |
+----------+
1 row in set (0.01 sec)
what i would like to get:
+----------+
| timeleft |
+----------+
| 04:32:57 |
+----------+
1 row in set (0.01 sec)
The times may be a little off in my example obviously because of the timediff() but hopefully you understand my issue. There must be an easy solution that i'm missing but i've spent half a day googleing to get to this point but timediff just won't cut me some slack.
Please and thank you!
PS. I haven't found the solution yet but i think i found what might cause the problem. Obvioysly the substraction is done by using absolute values 'estimate' column doesn't use seconds as it's absolute value and the result is completely wrong.
mysql> select abs(estimate) from t1;
+----------+
| abs(estimate) |
+----------+
| 50000 |
+----------+
1 row in set (0.00 sec)
and
mysql> select abs(timediff(now(),timestamp)) from t1;
+--------------------------------+
| abs(timediff(now(),timestamp)) |
+--------------------------------+
| 2318 |
+--------------------------------+
1 row in set (0.00 sec)
So is there an easy way to force mysql to use seconds on a time column? or is something wrong with my table and the estimate format is wrong?
use timediff like that :-
timediff(estimate,timediff(now(),timestamp))
your query :-
select timediff(estimate,timediff(now(),timestamp))
as timeleft from t1;

Is it possible to configure MySQL to return TIMESTAMP value as a UNIXTIMESTAMP?

Is it possible to configure MySQL to return TIMESTAMP value as a UNIXTIMESTAMP by default, rather than casting every column in the SELECT statement?
MySQL has a function to convert a date to a unix timestamp.
https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_unix-timestamp
mysql> SELECT UNIX_TIMESTAMP();
-> 1196440210
mysql> SELECT UNIX_TIMESTAMP('2007-11-30 10:30:19');
-> 1196440219
You cannot do that in MySQL configuration.
You can do that on application level - e.g. in PHP, you can use the mysqli_result::fetch_fields() method to detect timestamp type and convert it, other connectors will have similar methods.
Or you can do it - as suggested - using UNIX_TIMESTAMP() function on timestamp columns.
It sounds as though you want a different view of the same data:
mysql> select * from t;
+------+---------------------+
| data | ts |
+------+---------------------+
| foo | 2013-03-19 16:54:45 |
+------+---------------------+
1 row in set (0.00 sec)
mysql> select data, unix_timestamp(ts) from t;
+------+--------------------+
| data | unix_timestamp(ts) |
+------+--------------------+
| foo | 1363712085 |
+------+--------------------+
1 row in set (0.00 sec)
mysql> create view tv (data, time_t) as select data, unix_timestamp(ts) from t;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from tv;
+------+------------+
| data | time_t |
+------+------------+
| foo | 1363712085 |
+------+------------+
1 row in set (0.00 sec)

MySQL aggregate function problem

In the following example, why does the min() query return results, but the max() query does not?
mysql> create table t(id int, a int);
Query OK, 0 rows affected (0.10 sec)
mysql> insert into t(id, a) values(1, 1);
Query OK, 1 row affected (0.03 sec)
mysql> insert into t(id, a) values(1, 2);
Query OK, 1 row affected (0.02 sec)
mysql> select * from t
-> ;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
| 1 | 2 |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from t where a < 4;
+------+------+
| id | a |
+------+------+
| 1 | 1 |
| 1 | 2 |
+------+------+
2 rows in set (0.00 sec)
mysql> select * from t where a < 4 having a = max(a);
Empty set (0.00 sec)
mysql> select * from t where a < 4 having a = min(a);
+------+------+
| id | a |
+------+------+
| 1 | 1 |
+------+------+
1 row in set (0.00 sec)
The HAVING clause is used to filter groups of rows. You reference min(a) and max(a) which (in the absence of any GROUP BY clause) aggregate over all a values in the table but then use a comparison against a single a value.
So which a value is MySQL supposed to use? All other RDBMSs that I know of would throw an error at this point however MySQL does allow this. From the docs
Standard SQL does not permit the HAVING clause to name any column
not found in the GROUP BY clause unless it is enclosed in an aggregate
function. MySQL permits the use of such columns to simplify
calculations. This extension assumes that the nongrouped columns will
have the same group-wise values. Otherwise, the result is
indeterminate.
So in your case from the results you are getting it appears that it ended up using 1 as the scalar value for a but this behaviour is not guaranteed and it could equally well have used 2 or any other existing a value.