How to assign variables without displaying? - mysql

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

Related

How to replace multiple values in 1 column in mysql SELECT query using REPLACE()?

I have a table with Boolean values (0 and 1 only) that needs to be CSV-ed to a client. I know I can do 1 replace like this:
SELECT REPLACE(email, '%40', '#'),
REPLACE(name,'%20', ' '),
REPLACE(icon_clicked, 1, 'Yes')
FROM myTable
WHERE id > 1000;
This will convert all the values of 1 to 'Yes', but how to do this in a single query for both 1 => Yes and 0 => No so Boolean result is stored in a single column? I tried to do this:
SELECT REPLACE(email, '%40', '#'),
REPLACE(name,'%20', ' '),
REPLACE(icon_clicked, 1, 'Yes'),
REPLACE(icon_clicked, 0, 'No')
FROM myTable
WHERE id > 1000;
But this query created an additional column for the 'No' string replace (so final result had 4 columns, email, name, icon_clicked->yes, icon_clicked->no)
One way is to nest REPLACE:
SELECT REPLACE(REPLACE(icon_clicked, 0, 'No'), 1, 'Yes')), ...
FROM myTable
...
or use CASE WHEN (this will work for most RDBMS comparing to IF function which is MySQL related):
SELECT CASE WHEN icon_clicked THEN 'Yes' ELSE 'No' END, ...
FROM myTable
...
SqlFiddleDemo
EDIT:
There is also one nice way utilizing ELT:
SELECT icon_clicked,
ELT(FIELD(icon_clicked,0,1),'No','Yes'),
ELT(icon_clicked + 1, 'No', 'Yes')
FROM mytable
SqlFiddleDemo2
No need to use nested Replace or Case statement. Try using IF, which is way simpler
SELECT
icon_clicked,
IF(icon_clicked,'Yes','No')
FROM myTable
SQL FIDDLE DEMO

MySQL trigger concat with curdate()

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'
)
)

Mysql logic - how to change the selected value based on the data?

I am trying to populate a table with phone number from a temp table. I have wrote the query with no problem. but my peoblem here is to know if the company already has a primary number or not
so I select 2 fields from my temp table called "cvsnumbers" 1) company_code (id) and the phone number.
I need to add a case statement to change the value of a main_number field. so if the number already has a number with main_number = 1 then I need to insert 0 for the new phone number but if there is no main_number then I need to insert 1 for the new phone number making it a primary phone number for the account.
this is my query
SELECT ac.account_id,
REPLACE(REPLACE(REPLACE(REPLACE(ta.phone_number, '-', ''), ' ', ''), ')', ''),'(','') AS Phone,
IFNULL(ta.ext, '') AS extention,
IFNULL(ta.main_number, 0) AS MainNumber,
ta.type AS contact_type,
'2' AS created_by
FROM cvsnumbers AS ta
INNER JOIN accounts AS ac ON ac.account_id = ta.company_code
WHERE LENGTH(REPLACE(REPLACE(REPLACE(REPLACE(ta.phone_number, '-', ''), ' ', ''), ')', ''),'(','') ) = 10
AND REPLACE(REPLACE(REPLACE(REPLACE(ta.phone_number, '-', ''), ' ', ''), ')', ''),'(','') NOT IN (SELECT contact_number FROM contact_numbers)
My issue is
`IFNULL(ta.main_number, 0) AS MainNumber,`
I want to change that to some what a case statment to check if a company_code already has a main_number or not.
How can I change this?
Thanks
I am still not sure exactly how your query should look like, but how about something along theese lines?
SELECT CASE
WHEN EXISTS (SELECT *
FROM contact_numbers
WHERE main_number = 1
AND contact_number =
<insert contact number from outer expression here>)
THEN 1
ELSE 0
END AS MainNumber
FROM ...

mysql : turn fraction strings into number

I have strings like... "3/4" and "5/9" and some like... "1/2 km" and "3/4 degree" stored in mysql columns.
I would like to convert them into numbers.
In first case, 3/4 ==> .75.
In more complicated second case, strip off units like "km" and "degree" so
"1/2 km" ==> 0.5.
I think this isn't something you should do in a query, but rather calculate it when it is stored and save the calculated value in the table next to its text value.
But if you want to, you can use some string functions to slice up the value and the do the math yourself:
select
x.Multiplier / x.Divider as Result
from
(select
cast( substr( t.String,
1,
locate('/', t.String) - 1)
as decimal)
as Multiplier,
cast( substr( t.String,
locate('/', t.String) + 1,
locate( ' ',
concat(t.String, ' ')))
as decimal)
as Divider
from
YourTable t) x
Note however, that this may cause trouble if the data is 'invalid'. If it says '0/0 km', it may fail, if it contains 'no data here' it may fail as well.
The above didn't quite work for me so came up with this which does. The query works for '10', '3/4' and '10 3/4'. Obviously you should replace the constructed rows at the bottom with your string or a selected value from a table:
SELECT
IF (
LOCATE(' ',fraction) > 0 OR LOCATE('/',fraction) = 0,
SUBSTRING_INDEX(SUBSTRING_INDEX(fraction,'/','1'),' ','1')
,0
) AS `integer`,
IF (
LOCATE('/',fraction) > 0,
SUBSTRING_INDEX(SUBSTRING_INDEX(fraction,'/','1'),' ','-1'),
0
) AS numerator,
SUBSTRING_INDEX(fraction,'/','-1') AS denominator,
(SELECT `integer`) + ((SELECT numerator) / (SELECT denominator)) AS `decimal`
FROM (
SELECT '10 3/4' AS fraction
UNION SELECT '10'
UNION SELECT '3/4'
) t;
With PHP you could do:
// assuming $vals has the values from the database
$converted = array();
foreach ($vals as $key => $val) {
preg_match("/^(\\d+)\\/(\\d+)/", $val, $matches)
if (count($matches) > 2) {
$numerator = (int) $matches[1];
$denominator = (int) $matches[2];
$converted[$key] = (float) $numerator / $denominator;
}
}

Increase Alphanumeric VARCHAR Entry by Value 1?

On an old project because of not thought through design I have a column which actually should be set to auto_increment, though it cannot be because it are alphanumeric entries as follows:
c01
c02
c03
(c99 would continue to c100 and more), the letter happened in the past and it would require to overhaul the system to take it out, thus I rather prefer this workaround.
Now I need a way to imitate the auto_increment functionality with the SQL statement myself, my own attempt has gotten as far as the following:
INSERT INTO tags (tag_id, tag_name, tag_description, added_by_user_id, creation_date, last_edited) VALUES (SELECT(MAX(tag_id)+1),
'Love', 'All about love', 7, now(), 0);
This one does not work as is, though the idea was to select the highest entry in the column "tag_id" and then simply increase it by the value 1.
Any ideas how to accomplish this?
By the way I am also not sure if you simply can increase an alphanumeric entry through this way, though I know it can be done, I just don't know how.
If you want to safely get the largest integer value of a tag id of the form c##.., you could use the following expression:
max( convert( substring(tag_id, 2) , unsigned integer) )
^^^ largest ^^^^^^^^^ after 'c' ^^^^^^^^^^^^^^^^ convert to positive number
Then your insert statement would look something like this:
set #newid = convert(
(select
max(convert( (substring(tag_id, 2)) , unsigned integer))+1
from tags), char(10)
);
set #newid = if(length(#newid) = 1, concat('0', #newid), #newid);
set #newid = concat('c', #newid);
INSERT INTO tags (tag_id, tag_name, tag_description, added_by_user_id,
creation_date, last_edited)
VALUES (#newid, 'Love', 'All about love', 7, now(), '2012-04-15');
Demo: http://www.sqlfiddle.com/#!2/0bd9f/1
this will increase from c01 to c02 to c03 ... to c99 to c100 to c101 ... to c999 to c1000 etc.
set #nextID = (SELECT CONCAT(SUBSTRING(`tag_id`, 1, 1), IF(CHAR_LENGTH(CAST(SUBSTRING(`tag_id`, 2)
AS UNSIGNED)) < 2, LPAD(CAST(CAST(SUBSTRING(`tag_id`, 2) AS UNSIGNED) + 1 AS CHAR), 2,
'0'), CAST(CAST(SUBSTRING(`tag_id`, 2) AS UNSIGNED) + 1 AS CHAR))) FROM `tags` ORDER BY
`tag_id` DESC LIMIT 1);
INSERT INTO tags (tag_id, tag_name, tag_description, added_by_user_id,
creation_date, last_edited) VALUES (#nextID, 'Love', 'All about love', 7, NOW(), null);