MySQL trim multiple 0 of string? - mysql

So I have a column of strings in a format like this: '123.123.123.123.123'.
I need to cut the string to the first two numbers like so: '123.123' that way I can GROUP BY the cut string to get the results needed.
I can do this easily by using SUBSTRING_INDEX(Version, '.', 2) however the problem arises when the second number part has multiple 0's therefore giving me duplicate entries in the query.
e.g. (10.00, 10.0) and 10.404, 10.4040 etc.
Is there a way to trim all unwanted zeros off the end of the string?
Note: I can only use straight MySQL or functions in this case.
EDIT:
I can get the desired result by replacing the first instance of '.0', trim the extra zeros and then replace the '.0' back
REPLACE(TRIM(TRAILING '0' FROM REPLACE(SUBSTRING_INDEX(Version, '.', 2), '.0', '^a')), '^a', '.0')
This probably is not the best option performance wise - therefore I will wait for others before accepting my own.

If you are only working with the first two components, then convert the values to a number, say:
cast(substring_index(version, '.', 2) + 0 as decimal(10, 4))
This will give everything with equal numeric values the same representation.
EDIT:
If you want to remove the trailing zeros from the end of the string, you can use this trick:
replace(rtrim(replace(substring_index(version, '.', 2), '0', ' ')), ' ', '0')
This replaces the zeros with spaces, then uses rtrim() and converts them back to zeroes.

Related

Mysql: extract a string from field between delimiters (backwards)

I have a Column 'ACCOUNT_NUMBER' from a table 'BankingActivity' which contains data as follow :
example:
ManualBanking-BankDeposit-350-1006590343--INTERNAL_A
or
MyPayCard-MyPayDeposit-620-989228234--TL
I need to extract the number '1006590343' or '989228234'
Initially i execute the following query:
select substr( `BankingActivity`.`ACCOUNT_NUMBER`,(
locate( '--', `BankingActivity`.`ACCOUNT_NUMBER` ) - 9 ),9 ) * 1
from BankingActivity
Which works fine if the length of the string does not exceed 9 digits. Over 9 digits, I obviously have issues and can not get the full string.
How can i look backwards for the delimiter '--' and then extract the value between the '--' delimiter and the previous '-' delimiter?
I tried with some Regex but I am not familiar enough with it to get a correct result.
Try
SELECT regexp_substr(
regexp_substr(acct, '-\\d+--'), '\\d+')
FROM (
SELECT 'ManualBanking-BankDeposit-350-1006590343--INTERNAL_A' as acct
UNION
SELECT 'MyPayCard-MyPayDeposit-620-989228234--TL'
) accounts;
The inner regexp_substr extracts a substring that begins with a dash followed by 1 or more digits and ends with two dashes. That would be e. g. '-1006590343--'. From this, the outer regexp_substr extracts all consecutive digits, that is '1006590343'.
More detailed information about regular expressions in MySQL can be found in the documentation.
If I have understood your question correctly then you can try something like this -
select SUBSTRING_INDEX(SUBSTRING_INDEX('ManualBanking-BankDeposit-350-1006590343--INTERNAL_A', '-' ,-3), '--', 1);
select SUBSTRING_INDEX(SUBSTRING_INDEX('MyPayCard-MyPayDeposit-620-989228234--TL', '-' ,-3), '--', 1);
This is probably a job for SUBSTRING_INDEX().
Check it out. Fiddle here.
SET #s = 'ManualBanking-BankDeposit-350-1006590343--INTERNAL_A';
SELECT SUBSTRING_INDEX(#s, '-', -3);
This splits your string on '-'. It takes everything after the third '-' delimiter from the end, and gives you back 1006590343--INTERNAL_A.
Then we use SUBSTRING_INDEX() again on that.
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(#s, '-', -3), '-', 1);
Lo and behold, this gets us 1006590343.
But. This is a brittle way to do it. MySQL's string processing isn't easy to program in detailed ways. This solution doesn't take into account things like missing dashes at the end of the string. Garbage in, garbage out. Use a host language like C# / php / nodejs / Java etc to do this kind of string analysis if you want it to be super-robust for real world data.

SQL Query on editing a quantity field

I have a dataset where the values are different, and I want to bring them into a single format.The values are stored as varchar
For ex.
1st Case: 1.23.45 should be 123.45
2nd Case: 125.45 should be 125.45
The first one, has two decimals. I want to remove the first decimal only(if there are 2) else let the value be as it is.
How do I do this?
I tried using replace(Qty,'.',''). But this is removing of them.
I think this can do (although I am not 100% sure about corner cases)
SET Qty = SUBSTRING(Qty, 1, LOCATE(Qty, '.') - 1) + SUBSTRING(Qty, LOCATE(Qty, '.') + 1, LENGTH(Qty) - LOCATE(Qty, '.') - 1)
WHERE LENGTH(Qty) - LENGTH(REPLACE(Qty, '.', '')
You can use a regular expression to handle this case.
Assuming there are only two decimals in your string the below query should be able to handle the case.
select (value,'^(\d+)(\.)?(\d+\.\d+)$',concat('$1','$2')) as a
Here we are matching a regular expression pattern and capturing the following
digits before first decimal occurrence in group one
digits before and after last decimal occurrence including the last decimal in group two.
Following that we are concatenating the two captured groups.
Note that the first decimal has been made optional using ? character and hence we are able to handle both type of cases.
Even if there are more than two decimal cases, I believe a properly constructed regular expression should be able to handle it.

MySQL update all the strings that start with same prefix but deleting only the part that starts with an underscore

In the column value of table image of a mysql database I have a lot of different url of images.
They all have the same prefix prefix- followed by 5 different characters and numbers, for example:
prefix-SD356
prefix-RV954
prefix-UB347
Unfortunately after that, I alway have an underscore followed by other characters, numbers and underscore which I would like to delete but keeping the first part.
To better understand:
this prefix-SD356_2_25.jpg should become prefix-SD356.jpg
this prefix-RV954_1.jpg should become prefix-RV954.jpg
this prefix-UB347_1_1.jpg should become prefix-UB347.jpg
and so on...
I would need a query where I can update all the string that begin with prefix- [A-Za-z0-9] keeping that part and delete the rest that starts with _
Based on what you say:
select concat(left(string, 12), '.', substring_index(string, '.', -1))
This is easily incorporated into an update:
update t
set string = concat(left(string, 12), '.', substring_index(string, '.', -1))
where string like 'prefix______%.%';

Using COALESCE in MySQL

I'm just getting used to MySQL, I've come from a SQL Server background...
This SQL query builds an address how it should in SQL Server, how can I adapt it to use within MySQL. When I run it in SQL Server it displays all the data within each field, when run in MySQL it just shows me the first field.
Why would this be, what should I do different in MySQL?
SELECT COALESCE(House, '') + ' ' + COALESCE(StreetName, '') + ' ' + COALESCE(TownCity, '') + ' ' + COALESCE(Postcode, '') AS Display
FROM MyTable
WHERE Postcode LIKE '%A1 2AB%'
Use the concat() function:
SELECT concat(COALESCE(House, ''), ' ', COALESCE(StreetName, ''), ' ',
COALESCE(TownCity, ''), ' ', COALESCE(Postcode, '')
) AS Display
FROM MyTable
WHERE Postcode LIKE '%A1 2AB%';
You can also do this with concat_ws(). This eliminates the need for all the spaces:
SELECT concat_ws(COALESCE(House, ''), COALESCE(StreetName, ''),
COALESCE(TownCity, ''), COALESCE(Postcode, '')
) AS Display
FROM MyTable
WHERE Postcode LIKE '%A1 2AB%';
What happens in MySQL is that the + does just what you expect: it adds numbers. A string that contains a number is converted to a number automatically, with silent errors for strings that have no numbers. In practice, this means that a string that starts with a non-digit (and non-decimal point) is converted to a 0.
So, house, which presumably usually numeric, is converted to a number just fine. All the other strings are converted to numbers but become zero and the house number is not changed. You would have gotten much different results if your post codes were American-style zip codes (which are typically numeric).
EDIT:
As #fthiella points out, the coalesce() is not necessary for concat_ws(). The two statements would do different things, because NULLs in the original query result in repeated separators. NULLs in the concat_ws() version would have only a single separator (which might be desirable).
However, I would tend to keep the coalesce() anyway. The behavior of concat() and concat_ws() varies in this regard. concat() returns NULL if any of its arguments is NULL. concat_ws() skips NULL arguments after the initial separator. Who can remember that distinction? It sounds like a recipe for confusion in production code. So, I would also use coalesce() even though it is optional.

MySQL IFNULL CONCAT

I'm working on a query in which I have a column of account numbers, which I've formatted by using a CONCAT statement to make the numbers 1-11111 instead of 11111.
There is a column with prior account numbers, however this value is NULL unless there is actually a prior account number. To try to only format the account numbers if they exist, I did this:
IFNULL(CONCAT(LEFT(a.prior_acct, 1), '-', RIGHT(a.prior_acct, 5)), 0) AS prior_account
Now, this is properly formatting the account numbers that are there, into the 1-11111 format. However the NULL fields are returning with the hypen and not a 0 (equally acceptable would be a blank space).
I tried adding in an extra set of parenthesis around the full concat statement to see if that would take away the hyphen but no luck!
What am I missing? TIA!
Your query should work as it is unless you are actually storing empty string in prior_acct , not NULL.
SELECT IFNULL(CONCAT(LEFT('', 1),'-',RIGHT('', 5)),0); -- outputs -
SELECT IFNULL(CONCAT(LEFT(null, 1),'-',RIGHT(null, 5)),0); --outputs 0
It's not Oracle where empty string and NULL are the same. If you need to treat empty string as null , you need to specify it's explicitly. One way is
IFNULL(CONCAT(
IF(
TRIM(LEFT('', 1))='',NULL, TRIM(LEFT('', 1))
),
'-', RIGHT(a.prior_acct, 5)), 0) AS prior_account