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

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

Related

How to extract specifc part from a string in 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

Custom SQL query, for sorting values with "-" as separators

I am trying to create an ORDER BY to sort my values properly.
The values contain a string and anywhere from zero to three sets of numbers separated by a -.
Example:
dog-2-13
dog-13-54-3
dog-25
cat-63-12
cat
I want them to be sorted firstly by the string in front and then by each of the "number sections" so that: dog-2-14 > dog-2-13 but dog-1-14 < dog-2-13.
Expected result (with more examples to make it clearer):
cat
cat-63-12
dog-2-13
dog-2-14
dog-3
dog-13-53-3
dog-13-54-3
dog-13-54-4
dog-25
I'm a SQL novice and completely lost. Thank you!
Please try...
SELECT fieldName
FROM
(
SELECT fieldName AS fieldName,
SUBSTRING_INDEX( fieldName,
'-',
1 ) AS stringComponent,
CONVERT( SUBSTRING_INDEX( SUBSTRING( fieldName,
CHAR_LENGTH( SUBSTRING_INDEX( fieldName, '-', 1 ) ) + 2 ),
'-',
1 ),
UNSIGNED ) AS firstNumber,
CONVERT( SUBSTRING_INDEX( SUBSTRING( fieldName,
CHAR_LENGTH( SUBSTRING_INDEX( fieldName, '-', 2 ) ) + 2 ),
'-',
1 ),
UNSIGNED ) AS secondNumber,
CONVERT( SUBSTRING( fieldName,
CHAR_LENGTH( SUBSTRING_INDEX( fieldName, '-', 3 ) ) + 2 ),
UNSIGNED ) AS thirdNumber
FROM table1
ORDER BY stringComponent,
firstNumber,
secondNumber,
thirdNumber
) tempTable;
The inner SELECT grabs the field name (which I am assuming is fieldName) and the three components and places each in a separate field and assigning an alias to that field. Each subfield must be included at this point for sorting purposes. The list is then sorted based upon those values.
Once this sorting is performed the outer SELECT chooses the original field from the list in a now sorted order.
The four outer instances of SUBSTRING_INDEX() are used to grab the desired fields from their first argument. As SUBSTRING_INDEX() grabs all of the string from the beginning to just before the first occurence of the delimiting character this makes finding the first field easy (Note : I am assuming that the first field shall contain no hyphens).
The first argument for the remaining occurences of SUBSTRING_INDEX() is formed by using SUBSTRING() to grab everything from just after the parsed part of fieldName and the following delimiting character. It is told where this is by using CHAR_LENGTH() to count the number of characters before the most recent delimiting character then adding 1 for the most recent delimiting character and another 1 to point SUBSTRING() to the character after the most recent delimiting character.
SUBSTRING_INDEX() will return NULL where it encounters an absent numerical field. Please note that NULL has a different sort value from zero.
The numerical fields are converted into unsigned Integers using CONVERT(). Unsigned integers were chosen as the supplied data does not contain any real numbers. If there are real values then you will need to replace UNSIGNED with DECIMAL. I have also assumed that all of the numbers will be positive.
Further reading...
https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_substring-index
https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_substring
https://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_char-length
https://dev.mysql.com/doc/refman/5.7/en/cast-functions.html#function_convert
If you have any questions or comments, then please feel free to post a Comment accordingly.
You can use a Query like this:
SELECT *
FROM yourTable
ORDER BY SUBSTRING_INDEX( SUBSTRING_INDEX(cat,'-',2), '-', -1);
sample
mysql> SELECT SUBSTRING_INDEX('dog-13-54-4','-',2);
+--------------------------------------+
| SUBSTRING_INDEX('dog-13-54-4','-',2) |
+--------------------------------------+
| dog-13 |
+--------------------------------------+
1 row in set (0,00 sec)
mysql>
mysql> SELECT SUBSTRING_INDEX( SUBSTRING_INDEX( 'dog-13-54-4','-',2), '-', -1);
+------------------------------------------------------------------+
| SUBSTRING_INDEX( SUBSTRING_INDEX( 'dog-13-54-4','-',2), '-', -1) |
+------------------------------------------------------------------+
| 13 |
+------------------------------------------------------------------+
1 row in set (0,00 sec)
mysql>

MySQL - Return from a string the leftmost characters from 2 different characters

I have a database with some codes seperated by / or -, I want to show the left side only, this is an example of the data:
45/84
12/753
68-53
15742-845
2/556
So, i want to get this:
45
12
68
15742
2
I tried using LEFT(), but this search for 1 character only, and returns a warning if the character is not found, this is what LEFT(field,'/') returns.
45
12
(WARNING)
(WARNING)
2
So, what about a REGEXP?
an IF?
any way to ignore from the first non numeric character?
I dont' have more ideas...
Thank you!
Try this:
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(col, '-', 1), '/', 1)
FROM mytable
Demo here
You can do it with this statement. Replace the string '15742/845' with your fieldname
SELECT SUBSTRING_INDEX( REPLACE('15742/845','/','-'), '-', 1)

Extract a set of digits from a string column in MySQL

I am trying to extract a fixed-length digits from a string column in MySQL, how can I go about doing so? The usual like and regexp doesn't work, so am pretty certain a function is needed, but unsure where to start and how to go about writing one.
Please advise.
The fixed-length digits are 10 digits and a sample of the string column:
'SGD0.00 AUTOMSG:'0179187381' is near Esso # 23:59.'
Please be advised the location of the 10 digits in the string varies.
Simple:
Just use: SUBSTR(str,x,y)
where:- str -> String,
x -> position,
y -> length
Example: SELECT SUBSTR('ABCDEFG',2,3); -> BCD
For more information visit this link:
http://www.w3resource.com/mysql/string-functions/mysql-substring-function.php
mysql> select substr("'SGD0.00 AUTOMSG:'0179187381' is near Esso # 23:59.'", 19,10);
+-----------------------------------------------------------------------+
| substr("'SGD0.00 AUTOMSG:'0179187381' is near Esso # 23:59.'", 19,10) |
+-----------------------------------------------------------------------+
| 0179187381 |
+-----------------------------------------------------------------------+
1 row in set (0.48 sec)
you may try like this:
SELECT SUBSTRING('Quadratically',5);
Syntax: SUBSTRING(str,pos)
For more info: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_substring
If the 10 digit number will always be preceeded with :' then you could use:
select substr(column_name, locate(":'", column_name) + 2, 10) from table_name
(assuming :' does not appear anywhere else before the number in the string)

count substring_index

i need to know how substring_index can only return all rows that match exactly the number of delimiters. In this case the .
For example this query:
SELECT
SUBSTRING_INDEX(ABC, '.', 4)
FROM xxx
only should output when the row is exactly something like this (with 4 words):
aaa.bbb.ccc.ddd
The problem is that: this row is also showed .
aaa.bbb
This will return anything where ABC has 3 . delimiters.
select *
from xxx
where char_length(replace(ABC, '.', '')) + 3 = char_length(ABC)
You would need to multiply 3 by your delimiter length if you had a multi-character string for your delimiter.