MySQL trigger concat with curdate() - mysql

i need a help to format this trigger output.
I need the output of the trigger have this format:
2013/0001
2013/0002
...
When year changes,
2014/0001
2014/0002
...
but my trigger generates that format:
00012013/
The trigger code is below:
SET NEW.num = CONCAT(
LPAD(COALESCE(
(SELECT MAX(LEFT(num, 4))
FROM `tb_numeros`
WHERE num LIKE DATE_FORMAT(CURDATE(), '%Y/____')), 0) + 1, 4, '0'),
DATE_FORMAT(CURDATE(), '%Y/'))

You can use indentation to clarify what's going on:
SET NEW.num = CONCAT(
LPAD(
COALESCE(
(
SELECT MAX(LEFT(num, 4))
FROM `tb_numeros`
WHERE num LIKE DATE_FORMAT(CURDATE(), '%Y/____')
), 0
) + 1, 4, '0'
),
DATE_FORMAT(CURDATE(), '%Y/')
)
It's clear that you get year on second place because, well, it's the second clause inside CONCAT().

I do not understand how you get the number sequence, however, I think you can simplify the code a bit:
...
SET `get_year` := YEAR(NOW());
SET `sequence` := (SELECT... WHERE... `num`... LIKE... `get_year`...); /* RETURN 0001 */
SET NEW.`num` := CONCAT(`get_year`, '/', `sequence`);
...

yeah! woRKS!!!
SET NEW.num = CONCAT(
DATE_FORMAT(CURDATE(), '%Y/'),
LPAD(
COALESCE(
(
SELECT MAX(RIGHT(num, 4))
FROM `tb_numeros`
WHERE num LIKE DATE_FORMAT(CURDATE(), '%Y/____')
), 0
) + 1, 4, '0'
)
)

Related

MySQL query error "Subquery returns more than 1 row" where update into the same table

How to update to the same table? i tried to do fraction conversion and update 1 of the rows in the same table but the error "Subquery returns more than 1 row"
Below are the code, (State1 is the table itself, Share field consists of those fraction data like 1/2,1/5 ..)
UPDATE State1 set shareresult =(SELECT
x.Multiplier / x.Divider as Result
from
(select
cast( substr( t.share,
1,
locate('/', t.share) - 1)
as decimal)
as Multiplier,
cast( substr( t.Share,
locate('/', t.Share) + 1,
locate( ' ',
concat(t.Share, ' ')))
as decimal)
as Divider
from
State1 t ) x)
thanks
Finally, i managed to solve my problem with the code below
CREATE TEMPORARY TABLE activity_product_ids AS SELECT x.NumberID, x.Multiplier / x.Divider as Result from (select cast( substr( t.share, 1, locate('/', t.share) - 1) as decimal) as Multiplier, cast( substr( t.Share, locate('/', t.Share) + 1, locate( ' ', concat(t.Share, ' '))) as decimal) as Divider, t.ID as numberID from State1 t) x;
UPDATE State1 a
JOIN activity_product_ids b
ON a.ID=b.NumberID
SET a.shareresult=b.Result;
Thanks for all the replies.
Neither your update statement nor the sub-query has a WHERE clause so it looks like you are trying to update every row with fraction to decimal conversion of every row.
This is a much simpler approach -
UPDATE State1
SET shareresult = ROUND(SUBSTRING_INDEX(share, '/', 1) / SUBSTRING_INDEX(share, '/', -1), 2)
WHERE id = 1;

How to format timestamp from mysql select query to exclude the unnecessary zeros in HH:MM:SS?

I have a select query:
string checkprogress = "SELECT TIMEDIFF(CURRENT_TIMESTAMP,timestamp) FROM times";
Which in return gives me a format with unnecessary leading zeros...
00:01:39 //(hours:minutes:seconds)
How can I alter this query or alter my c# code so that my string excludes all the unnecessary zeros in the timestamp?
Keep in mind that if the time reaches over 24 hours, the string will become:
1.00:01:39 //(day.hours:minutes:seconds)
the format above is completely fine since a day value is incorporated, so the format change I'm looking for is strictly for when the DAY value is not in effect (A.K.A when time is under 23:59:59).
It isn_t pretty, but it works.
SET #endDate = '2020-06-27 10:02:00';
SET #startDate = '2020-06-26 12:59:01';
SELECT
CONCAT(
IF(FLOOR(TIMESTAMPDIFF(SECOND, #startDate, #endDate) / 86400) > 0,CONCAT(FLOOR(TIMESTAMPDIFF(SECOND, #startDate, #endDate) / 86400), '.'),''),
LPAD(FLOOR((TIMESTAMPDIFF(SECOND, #startDate, #endDate) % 86400)/3600),2,'0'), ':',
LPAD(FLOOR((TIMESTAMPDIFF(SECOND, #startDate, #endDate) % 3600)/60),2,'0'), ':',
LPAD((TIMESTAMPDIFF(SECOND, #startDate, #endDate) % 60),2,'0')
);
Result 21:02:59
SET #endDate = '2020-06-27 10:02:00';
SET #startDate = '2020-06-26 09:59:01';
SELECT
CONCAT(
IF(FLOOR(TIMESTAMPDIFF(SECOND, #startDate, #endDate) / 86400) > 0,CONCAT(FLOOR(TIMESTAMPDIFF(SECOND, #startDate, #endDate) / 86400), '.'),''),
LPAD(FLOOR((TIMESTAMPDIFF(SECOND, #startDate, #endDate) % 86400)/3600),2,'0'), ':',
LPAD(FLOOR((TIMESTAMPDIFF(SECOND, #startDate, #endDate) % 3600)/60),2,'0'), ':',
LPAD((TIMESTAMPDIFF(SECOND, #startDate, #endDate) % 60),2,'0')
)
Result 1.00:02:59
If you're using MySQL 8+, you can use REGEXP_REPLACE:
SELECT REGEXP_REPLACE('00:01:39', '^[0:]+(\\d)', '$1')
For earlier versions, you can call TRIM twice, the first to trim leading 00:s from the string, and then to trim any further leading 0s:
SELECT TRIM(LEADING '0' FROM TRIM(LEADING '00:' FROM '00:01:39'))
In both cases the output is
1:39
There is one caveat on the TRIM method, if the result can be 00:00:00 the output will be an empty string. That can either be dealt with in your application, or you can use an IF expression to check for it:
IF(TIMEDIFF(t1, t2) = '00:00:00', 0, TRIM(LEADING '0' FROM TRIM(LEADING '00:' FROM TIMEDIFF(t1, t2))))
Demo on dbfiddle

How to assign variables without displaying?

Below is a really scaled down version of my SELECT statement.
SELECT
start_date,
IFNULL(#stop_date := HAIRY_CALCULATION(this_date, that_date)), '') as stop_date,
IF(#stop_date = '', 0, DATEDIFF(#stop_date, start_date)) as elapsed_days
FROM mytable
I'd like to put the elapsed_days as the second column, but it depends on the existence of the #stop_date variable.
How could I do something like below where I'm assigning the variable without displaying so I can use the variable later in the column calculations?
SELECT
DO_NOT_DISPLAY(#stop_date := IFNULL(HAIRY_CALCULATION(this_date, that_date), '')),
start_date,
IF(#stop_date = '', 0, DATEDIFF(#stop_date, start_date)) as elapsed_days,
#stop_date as stop_date
FROM mytable
You can always SELECT from a SELECT to narrow down what data you want to propagate:
SELECT stop_date, elapsed_days FROM
(SELECT
start_date,
IFNULL(#stop_date := HAIRY_CALCULATION(this_date, that_date)), '') as stop_date,
IF(#stop_date = '', 0, DATEDIFF(#stop_date, start_date)) as elapsed_days
FROM mytable) as subset
Note nothing is ever "displayed" except by your client. You're talking about manipulating what ends up in your result sets.
If this is something you're doing frequently and the logic behind it is unlikely to change arbitrarily you might want to wrap this up in a view so you can do something like:
SELECT stop_date, elapsed_days FROM mytable_hairy_view
Edit: Here's a possible two-pass approach:
SELECT
start_date,
IF(stop_date = '', 0, DATEDIFF(stop_date, start_date)) AS elapsed_days
FROM
(SELECT
start_date,
HAIRY_CALCULATION(this_date, that_date) AS stop_date
FROM mytable) as stop_dates
I found one work around. Maybe not the best, but:
SELECT
CONCAT(
-- -------- The following are just variable assignments for later use; they're not displayed in this column.
SUBSTRING(
(#stop_date := IFNULL(HAIRY_CALCULATION(this_date, that_date), '')),
0
),
-- -------- end of variable assignments for later use
start_date
) as start_date,
IF(#stop_date = '', 0, DATEDIFF(#stop_date, start_date)) as elapsed_days,
#stop_date as stop_date
FROM mytable

Replace function with variable and use it in return value

I have sql query, where if the difference between 2 times is greater than 1440, then it will divide by 7, if not it will return the actual value. The problem is that I am repeating the code in the return value.
SELECT
'IF(TIMESTAMPDIFF(MINUTE, now(), end_at) > 1440, TIMESTAMPDIFF(MINUTE, now(), end_at)/ 7, TIMESTAMPDIFF(MINUTE, now(), end_at)) as minutesLeft'
FROM table
How can I replace the repeating code to look like this?
SELECT
'IF(TIMESTAMPDIFF(MINUTE, now(), end_at) > 1440, timestamp / 7, timestamp ) as minutesLeft'
FROM table
You can try using in-statement assignments:
set #diff = null;
SELECT #diff := TIMESTAMPDIFF(MINUTE, now(), end_at),
IF( #diff > 1440, #diff / 7, #diff) as minutesLeft
FROM table
Wrap the select in a sub-query if you just want one column returned.

MySQL Variable Substitution

I want to simplify the following using dynamic SQL like one could do in Transact SQL.
I want to do something like:
SET #s = replace(field_name, '_complete','')
and use #s instead of replace(field_name, '_complete','')
Please adive if possible and if so how.
My current code:
select distinct
if(instr(replace(field_name, '_complete',''),'_') <= 5
,left(replace(field_name, '_complete','')
,instr(replace(field_name, '_complete',''),'_') - 1
)
,replace(field_name, '_complete','')
) AS form_id ,replace(
if(instr(replace(field_name, '_complete',''),'_') <= 5,
mid(replace(field_name, '_complete',''),
instr(replace(field_name, '_complete',''),'_') + 1,
length(replace(field_name, '_complete','')) - instr(replace(field_name, '_complete',''),'_')
)
,replace(field_name, '_complete','')
),
'_',
' ') as form_name ,field_name from redcap_extract2use where field_name like '%_complete' order by 1;
The above would then be replaced with:
select distinct
if(instr(#s,'_') <= 5 ,left(#s,instr(#s,'_') - 1),#s ) AS form_id
,replace( if(instr(#s,'_') <= 5,
mid(#s,instr(#s,'_') + 1,length(#s) - instr(#s,'_')),#s), '_', ' ') as form_name
,field_name
from redcap_extract2use
where field_name like '%_complete'
order by 1;
and I would have an execute... to run the query
If I'm understanding your question correctly then you would want to use the PREPARE and the EXECUTE statements.
For example:
SET #s = replace(field_name, '_complete','');
PREPARE mystatement FROM
SELECT DISTINCT ...... ;
EXECUTE mystatement;