MySQL order by column with letters and numbers - mysql

I have this column in my table with shelf names
M2-8-3
N1-12-1
N1-3-8
N2-6-1
O1-11-3
O2-1-5
O2-10-1
O2-10-2
O2-10-6
O2-16-7
O2-17-6
O2-17-7
O2-4-2
When i order by it ascending it gives the result visible above but how could i write the query to get the result visible below
M2-8-3
N1-3-8
N1-12-1
N2-6-1
O1-11-3
O2-1-5
O2-4-2
O2-10-1
O2-10-2
O2-10-6
O2-16-7
O2-17-6
O2-17-7
The difference is in the position of N1-3-8 and O2-4-2

Try this:
SELECT col
FROM yourTable
ORDER BY SUBSTRING_INDEX(col, '-', 1),
SUBSTRING(SUBSTRING_INDEX(col, '-', -2),
1,
INSTR(SUBSTRING_INDEX(col, '-', -2), '-') - 1),
SUBSTRING_INDEX(col, '-', -1)
This is the brute force approach, where each of the three terms in the ORDER BY clause corresponds to a portion of your hyphenated string.

This may be a slightly simpler method:
order by substring_index(col, '-', 1),
substring_index(col, '-', -2) + 0,
col
This ends up converting the middle portion to a number for sorting purposes.

Related

normalize text in a field

I have a field with value like this 'DOOR-LEFT' and I want to change this to 'Door-LEFT'.
I came across this query on this site:
UPDATE tbl
SET field1 = CONCAT(UCASE(LEFT(field1, 1)),
LCASE(SUBSTRING(field1, 2)));
The above query changes 'DOOR-LEFT' to 'Door-left'. I do not want anything after the - to be updated. So it should be 'Door-LEFT'.
How can I do this?
You can use sustring_index() to split the string on '-', and then use the logic you already have at hand:
update tbl
set field = concat(
upper(left(substring_index(field1, '-', 1), 1)),
lower(substr(substring_index(field1, '-', 1), 2)),
'-',
upper(substring_index(field1, '-', -1))
)
The surrounding upper() in the last part of the string is not strictly needed for your sample string, which is all upper case to start with. I left it on purpose in case it might be useful for other cases (and it doesn't hurt anyway).

Replace the special characters

data = "Qwsdyz_qwrbc_bcD_qwEr"
What I need is:
remove all the _
all characters to be in lower
the starting letter should be caps for all the 4 like this (QwsdyzQwrbcBcdQwer)
whatever changes made in above statement should't change the result like if we changed like Qwsdqwqyz_qwrwqeqwebc_bcqwD_qqwwEr_dadakjas i need the result like QesdqwqyzQwrwqeqwebcBcqwdQqwwerDasakjas
Please help me with MySQL coding.
set #data="Qwsdyz_qwrbc_bcD_qwEr";
select lower(SUBSTRING_INDEX(#data,"_",1)) into #data1;
select ucase(left(SUBSTRING_INDEX(#data,"_",2),1)) into #data2;
select lower(SUBSTRING_INDEX(#data,"_",2)) into #data3;
select substring(reverse(SUBSTRING_INDEX(reverse(#data3),"_",1)),2) into #data4;
select reverse((lower(SUBSTRING_INDEX(#data,"_",3)))) into #data5;
select (reverse(SUBSTRING_INDEX(#data5,"_",1))) into #data6;
select ucase(left(#data6,1)) into #data7;
select substring(#data6,2) into #data8;
select reverse(#data) into #data9;
select reverse(lower(SUBSTRING_INDEX(#data9,"_",1))) into #data10;
select ucase(left(#data10,1)) into #data11;
select substring(#data10,2) into #data12;
select concat(#data1,#data2,#data4,#data7,#data8,#data11,#data12) data;
You can use split functions replied in this question. Do sub-string and find every splited strings first character with UPPER() function do it upper character and LOWER() function do other characters to lowercase. And finally join with CONCAT() function.
This is just a messy concat() and substring_index():
select concat(concat(upper(left(lower(substring_index(data, '_', 1)), 1)),
lower(substr(lower(substring_index(data, '_', 1)), 2))
),
concat(upper(left(lower(substring_index(substring_index(data, '_', 2), '_', -1)), 1)),
lower(substr(lower(substring_index(substring_index(data, '_', 2), '_', -1)), 2))
),
concat(upper(left(lower(substring_index(substring_index(data, '_', 3), '_', -1)), 1)),
lower(substr(lower(substring_index(substring_index(data, '_', 3), '_', -1)), 2))
),
concat(upper(left(lower(substring_index(substring_index(data, '_', 4), '_', -1)), 1)),
lower(substr(lower(substring_index(substring_index(data, '_', 4), '_', -1)), 2))
)
)
from (select 'Qwsdyz_qwrbc_bcD_qwEr' as data) x
SQL is not optimized for string manipulations. I would advise you to do this in another tool, such as Python, if that is possible.
Here is a db<>fiddle.

mysql replace last group of digits in IP address

I would like to replace the last digits of all IP:port's with a *.
For example: 192.168.1.1:2000 should become 192.168.1.*:2000
set #ip = '192.168.1.1:2000';
select concat(
substring_index(substring_index(#ip, ':', 1), '.', 3),
'.*:',
substring_index(#ip, ':', -1)
);
If you want to understand how it works run the following query:
set #ip = '192.168.1.1:2000';
select #ip
, substring_index(#ip, ':', 1)
, substring_index(#ip, ':', -1)
, substring_index(substring_index(#ip, ':', 1), '.', 3);
It will return
192.168.1.1 2000 192.168.1
You just need to concatenate the last two columns and the middle part (.*:)

Implement a search and if statement in select statement

I currently have the following:
if (SUBSTRING(data, 3), FIND_IN_SET ('"', data), REPLACE(data, '"', '')) AS column
But the result is always 0.
I want to use select SUBSTRING(data, 3) and if the substring contains comma then replace it with " ".
How can I do that?
SELECT REPLACE(SUBSTRING(data, 3), ',', ' ') FROM your_table;

Can MySQL split a column?

I have a column that has comma separated data:
1,2,3
3,2,1
4,5,6
5,5,5
I'm trying to run a search that would query each value of the CSV string individually.
0<first<5 and 1<second<3 and 2<third<4
I get that I could return all queries and split it myself and compare it myself. I'm curious if there is a way to do this so MySQL does that processing work.
Thanks!
Use
substring_index(`column`,',',1) ==> first value
substring_index(substring_index(`column`,',',-2),',',1)=> second value
substring_index(substring_index(`column`,',',-1),',',1)=> third value
in your where clause.
SELECT * FROM `table`
WHERE
substring_index(`column`,',',1)<0
AND
substring_index(`column`,',',1)>5
It seems to work:
substring_index ( substring_index ( context,',',1 ), ',', -1)
substring_index ( substring_index ( context,',',2 ), ',', -1)
substring_index ( substring_index ( context,',',3 ), ',', -1)
substring_index ( substring_index ( context,',',4 ), ',', -1)
it means 1st value, 2nd, 3rd, etc.
Explanation:
The inner substring_index returns the first n values that are comma separated. So if your original string is "34,7,23,89", substring_index( context,',', 3) returns "34,7,23".
The outer substring_index takes the value returned by the inner substring_index and the -1 allows you to take the last value. So you get "23" from the "34,7,23".
Instead of -1 if you specify -2, you'll get "7,23", because it took the last two values.
Example:
select * from MyTable where substring_index(substring_index(prices,',',1),',',-1)=3382;
Here, prices is the name of a column in MyTable.
Usually substring_index does what you want:
mysql> select substring_index("foo#gmail.com","#",-1);
+-----------------------------------------+
| substring_index("foo#gmail.com","#",-1) |
+-----------------------------------------+
| gmail.com |
+-----------------------------------------+
1 row in set (0.00 sec)
You may get what you want by using the MySQL REGEXP or LIKE.
See the MySQL Docs on Pattern Matching
As an addendum to this, I've strings of the form:
Some words 303
where I'd like to split off the numerical part from the tail of the string.
This seems to point to a possible solution:
http://lists.mysql.com/mysql/222421
The problem however, is that you only get the answer "yes, it matches", and not the start index of the regexp match.
Here is another variant I posted on related question. The REGEX check to see if you are out of bounds is useful, so for a table column you would put it in the where clause.
SET #Array = 'one,two,three,four';
SET #ArrayIndex = 2;
SELECT CASE
WHEN #Array REGEXP CONCAT('((,).*){',#ArrayIndex,'}')
THEN SUBSTRING_INDEX(SUBSTRING_INDEX(#Array,',',#ArrayIndex+1),',',-1)
ELSE NULL
END AS Result;
SUBSTRING_INDEX(string, delim, n) returns the first n
SUBSTRING_INDEX(string, delim, -1) returns the last only
REGEXP '((delim).*){n}' checks if there are n delimiters (i.e. you are in bounds)
Building on #Oleksiy's answer, here is one that can work with strings of variable segment lengths (within reasonable limits), for example comma-separated addresses:
SELECT substring_index ( substring_index ( address,',',1 ), ',', -1) AS address_line_1,
IF(address_parts > 1, substring_index ( substring_index ( address,',',2 ), ',', -1), '') AS address_line_2,
IF(address_parts > 2, substring_index ( substring_index ( address,',',3 ), ',', -1), '') AS address_line_3,
IF(address_parts > 3, substring_index ( substring_index ( address,',',4 ), ',', -1), '') AS address_line_4,
IF(address_parts > 4, substring_index ( substring_index ( address,',',5 ), ',', -1), '') AS address_line_5
FROM (
SELECT address, LENGTH(address) - LENGTH(REPLACE(address, ',', '')) AS address_parts
FROM mytable
) AS addresses
It's working..
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(
SUBSTRING_INDEX(SUBSTRING_INDEX(SUBSTRING_INDEX(col,'1', 1), '2', 1), '3', 1), '4', 1), '5', 1), '6', 1)
, '7', 1), '8', 1), '9', 1), '0', 1) as new_col
FROM table_name group by new_col;