How to extract specifc part from a string in MySQL - mysql

I am trying to extract a specifc part from a string in MySQL, however, I am unable to extract it correctly.
The pattern is the following:
-MB|{field_1}-AA|{field_2}-BB|{field_3}
This is the example
-MB|string1-AA|string2-BB|string3
I've written the following code to extract the last field, however it is not dynamic, and will only work, when we have a specific number of letters/numbers:
SELECT
test_string,
SUBSTRING(test_string, LOCATE( '|', test_string) + 1 - LOCATE( '|', test_string) - 9) as string3
FROM test_table;
The output is the whole string and then just the last part of it:
string3
Having this said, can someone suggest a syntax that I can use in order to extract:
the values between the 1st | and second |
the value between the 2nd | and the 3rd |
and a better way to extract everything after the 3rd |
Thank you in advance!

If you're going for the last string only, you can REVERSE() the string first then locate | and then use it to do SUBSTRING() on the reversed string.. THEN reverse it again to get the original string. There are three REVERSE() in total if you're going with SUBSTRING() without a subquery:
SELECT test_string,
REVERSE(SUBSTRING(REVERSE(test_string),1,LOCATE('|',REVERSE(test_string))-1))
FROM test_table;
If you're using a subquery, you can reduce the usage of REVERSE() to two, albeit with a longer query:
SELECT test_string,
REVERSE(SUBSTRING(rvstr,1,LOCATE('|',rvstr)-1))
FROM
(SELECT test_string,
REVERSE(test_string) rvstr
FROM test_table) a;
But you can avoid all that and just use SUBSTRING_INDEX
SELECT test_string,
SUBSTRING_INDEX(test_string, '|', -1)
FROM test_table;
You can use the same function to extract other string separated by the delimiter using something like this:
SELECT test_string,
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',1),'|',-1) AS 'Str1',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',2),'|',-1) AS 'Str2',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',3),'|',-1) AS 'Str3'
FROM test_table;
As for "way to extract everything after the 3rd", I think it's a bit tricky but maybe:
SELECT test_string,
Str1,Str2,Str3,
SUBSTRING(test_string,LENGTH(CONCAT(Str1,Str2,Str3))+4) AS 'StrAfter3rd'
FROM
(SELECT test_string,
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',1),'|',-1) AS 'Str1',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',2),'|',-1) AS 'Str2',
SUBSTRING_INDEX(SUBSTRING_INDEX(test_string,'|',3),'|',-1) AS 'Str3'
FROM test_table) v;
Getting the LENGTH() of the concatenated results of Str1 to Str3 with 3 of the original | re-added and + the last | before the 4th string (+4 in total), then use it for the SUBSTRING().
Demo fiddle

Related

sql extract only numeric value from column

I have a column called' memo_line_2',the value format is like :'$3000.00 (card limit increase)',how can I only extract numeric value from the column?Thanks
example:
'$3000.00 (card limit increase)' -> 3000
'$5000.00 (card limit increase)' -> 5000
'$12000.00 (card limit increase)' ->12000
You could use REGEXP_SUBSTR() for this:
SELECT REGEXP_SUBSTR(tmp.`value`, '[0-9]+') as `new_value`
FROM (SELECT '$3000.00' as `value` UNION ALL
SELECT '$5000.00' as `value` UNION ALL
SELECT '$12000.00' as `value`) tmp
Returns:
new_value
---------
3000
5000
12000
If you would like to keep everything after the decimal, use '[0-9.]+' as your regular expression filter.
If your data will be always in this format you can use below query to select the data between $ and . :
SELECT substring_index(substring_index(memo_line_2, '$', -1), '.', 1)
FROM your_table;
Refrence: MySQL substring between two strings
You can use:
select regexp_substr(col, '[0-9]+[.]?[0-9]*')
This will extract the digits with the cents. You can then convert to an integer or numeric:
select cast(regexp_substr(col, '[0-9]+[.]?[0-9]*') as unsigned)
It can be done by making a custom function in your sql query
Take a look at:
https://stackoverflow.com/a/37269038/16536522

MYSQL : Find the last occurrence of a character in a string

Length will be dynamic and i want to find the data before last occurrence of a character in a string in MYSQL
Like strrchr in php
To get last occurrence of _ (underscore) I need to pass length. and here it's 3
mysql> SELECT SUBSTRING_INDEX ('this_is_something_here', '_', 3);
+----------------------------------------------------+
| SUBSTRING_INDEX ('this_is_something_here', '_', 3) |
+----------------------------------------------------+
| this_is_something |
+----------------------------------------------------+
And here, to get last occurrence of _ (underscore) i need to pass length. and here it's 6
mysql> SELECT SUBSTRING_INDEX ('and_this_may_go_like_this_too', '_', 6);
+-----------------------------------------------------------+
| SUBSTRING_INDEX ('and_this_may_go_like_this_too', '_', 6) |
+-----------------------------------------------------------+
| and_this_may_go_like_this |
+-----------------------------------------------------------+
i want data string before last occurrence of _ (underscore) just shown in above example but without passing length.
Note : from above example i want before data of "_here" and "_too"
last occurrence of _ (underscore)
Is there any built-in functionality to achieve this in MySQL?
Thanks in advance amigos.
I didn't quite get your examples, but I think what you want is to pass -1 as the length and prepend the substring prior.
Compare
strrchr('and_this_may_go_like_this_too', '_'); // Returns _too
SELECT SUBSTRING_INDEX('and_this_may_go_like_this_too', '_', -1);
-- Returns too, just need to concatenate `_` so...
SELECT CONCAT('_', SUBSTRING_INDEX('and_this_may_go_like_this_too', '_', -1));
-- Returns _too
If you're looking for the part of the string before and up to the needle, and not from the needle to the end of the string, you can use:
SET #FULL_STRING = 'this_is_something_here';
SELECT LEFT(#FULL_STRING, LENGTH(#FULL_STRING) - LOCATE('_', REVERSE(#FULL_STRING)));
-- Returns this_is_something
Note that the second statement is not what strrchr does.
select reverse(substr(reverse('this_is_something_here'), 1+locate('_', reverse('this_is_something_here'))));
Use reverse, locate, right then replace without using length
Set #str = 'there_is_something';
Select replace(#str,right(#str,locate('_',reverse(#str))),'');
You can write query like this
SELECT SUBSTRING_INDEX('and_this_may_go_like_this_too','_',(LENGTH('and_this_may_go_like_this_too')-LENGTH(REPLACE('and_this_may_go_like_this_too' ,'_',''))) - 1);

MySQL sorting with alphanumeric prefix

I've got a database with a column that contains the following data:
aaa-1
aaa-2
aaa-3
...
aaa-10
aaa-11
...
aaa-100
aaa-101
...
aaa-1000
When I query and sort the data in ascending order, I get:
aaa-1
aaa-10
aaa-11
...
aaa-100
aaa-101
...
aaa-1000
...
aaa-2
...
aaa-3
Is this actually the correct (machine) way of sorting? Is the order being screwed up because of the aaa- prefix? How do I go about sorting this the way a human would (ie something that looks like the first snippet)?
P.S. If the problem does lie in the prefix, is there a way to remove it and sort with just the numeric component?
P.P.S. It's been suggested to me that I should just change my data and add leading zeroes like aaa-0001 and aaa-0002, etc. However, I'm loathe to go that method as each time the list goes up an order of 10, I'd have to reformat this column.
Thank you all in advance! :)
You can extract the number part, convert it to numeric data type and then do an ORDER BY:
SELECT mytable.*,
CAST(SUBSTRING_INDEX(mycolumn, '-', - 1) AS UNSIGNED) mycolumnintdata
FROM
mytable
ORDER BY mycolumnintdata;
If there are expressions which does not match number, the CAST function would return 0 and those records would be displayed first. You may handle this separately if needed.
I had a similar issue and the trick that did it for me was this one
*"ORDER BY LENGTH(column_name), column_name
As long as the non-numeric part of the value is the same length, this will sort 1 before 10, 10 before 100, etc."*
as given by Andreas Bergström on this question.
Hope that helps someone.
this is the alphabetical order,
you want numerical order,
for do this you must in the ORDER BY clause
trim the costant "aaa-" part
convert it in number
convert(SUBSTRING(val, 3), integer)
I will give you a sample sorting. Not based on your data sample, but this could help you out.
Say you have data like this :
id
----
1
2
6
10
13
when you do ORDER BY id ASC would return :
id
----
1
10
13
2
6
I suggest, use LPAD.
This query : SELECT LPAD('12',5,'0') return 00012
So when you have table data like I provide above, you can sort them like this :
SELECT * FROM TABLE
ORDER BY LPAD(ID,7,'0') ASC
Based on your data.
SELECT SUBSTR('aaa-100',5,LENGTH('aaa-100') - 3) return 100
So, SELECT LPAD( SUBSTR('aaa-100',5,LENGTH('aaa-100') - 3), 7, '0') return 00000100
So you can combine string function such as SUBSTR and LPAD. Do have any clue now?

Substring from last index

ABC:123 UVW XYZ NN-000
What is the best method to get the value after the last space using substr()? In this case I want to get NN-000 but also be able to get that last value in the case that it's greater than or less than 6 characters.
In Oracle, use SUBSTR and INSTR functions
SELECT SUBSTR('ABC:123 UVW XYZ NN-000', INSTR('ABC:123 UVW XYZ NN-000', ' ', -1))
AS LASTOCCUR
FROM DUAL
RESULT:
| LASTOCCUR |
-------------
| NN-000 |
Refer LIVE DEMO
In MySQL you could use reverse and substring_index:
select data,
rv,
reverse(substring_index(rv, ' ', 1)) yd
from
(
select data,
reverse(data) rv
from yt
) d;
See SQL Fiddle with Demo
In Oracle you could use reverse, substr and instr:
select data,
reverse(substr(rv, 0, instr(rv, ' '))) rv
from
(
select data, reverse(data) rv
from yt
) d
See SQL Fiddle with Demo
Combine the powers of RIGHT(),REVERSE() AND LOCATE()
SELECT RIGHT('ABC:123 UVW XYZ NN-000',LOCATE(' ',REVERSE('ABC:123 UVW XYZ NN-000'))-1)
EDIT: Locate in MYSQL, not CHARINDEX
REVERSE() reverses the string, so that the 'first' space it finds is really the last one. You could use SUBSTRING instead of RIGHT, but if what you're after is at the end of the string, might as well use RIGHT.

Sql Select into array - column has seperater

I have a column in my DB that has the following data (yeah i know its wrong to have multiple names separated by some random character)
"John Cusack | Thandie Newton | Chiwetel Ejiofor"
I want to be able to separate these people into an array to use later or even just to be able display them like below will help
John Cusack
Thandie Newton
Chiwetel Ejiofor
any ideas please
thanks in advance
As you say, storing delimited lists in an RDBMS really is not a good idea; however, you may be able to use MySQL's string manipulation functions such as SUBSTRING_INDEX() to obtain your desired results (MySQL doesn't have array types, so I assume you're merely looking to split the data):
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(my_column, '|', 1), -1),
SUBSTRING_INDEX(SUBSTRING_INDEX(my_column, '|', 2), -1),
SUBSTRING_INDEX(SUBSTRING_INDEX(my_column, '|', 3), -1)
FROM my_table
Note that one doesn't actually need to invoke SUBSTRING_INDEX() twice for the first and last elements of the list, but I thought it informative to do so in order that the pattern for further elements can be seen more clearly.
If you were so inclined, you could build a stored procedure that loops over the string populating a temporary table with each found element—but this is all so far away from "good practice" that it's almost certainly not worth delving into it any further.
you can try this.
select substring_index(substring_index('a|b|c|h', '|',#r:=#r+1),'|',-1) zxz
from (select #r:=0) x,
(select 'x' xx union select 'v' xx union select 'z' xx union select 'p' xx) z;
Result looks like
----
|zxz|
-----
|a |
------
|b |
------
|c |
------
|h |
------
locatet here: Mysql
and a little modified.
Remember: The "count" of the union statements have to be the same as your delemiter.
Kind Regars