MySQL - Sort alphabetical with numbers - mysql

I need to sort alphabetical but with numbers, but then alphabetical again???
If I do this...
ORDER BY name ASC
I get this...
2d this 10
2d this 9
this item
but I want this...
2d this 9
2d this 10
this item
so far I've done this...
ORDER BY CAST(name AS UNSIGNED) ASC
which gives me this...
this item
2d this 9
2d this 10
so it gets the d1 this 9 and d1 this 10 correct, but I need this item at the end.
I have been keeping it this way, then when looping through the results just check for this item, storing it and adding it to the results after the loop is finished, but is there any way to do it all within the sql query?

You can replace the numbers at the end of the string and use that for the first key in order by:
order by regexp_replace(name, '[0-9]*$', ''),
length(name),
name
In earlier versions of MySQL, you can remove the last numbers with a bit more pain:
order by (case when name regexp ' [0-9]+$'
then left(name, length(name) - instr(reverse(name), ' '))
else name
end),
length(name),
name
Here is a db<>fiddle.

For this sample data you can use the function substring_index():
select name
from tablename
order by substring_index(name, ' ', -1) + 0 = 0,
substring_index(name, ' ', -1) + 0,
name
See the demo.
Results:
| name |
| ---------- |
| 2a this 9 |
| 2a this 10 |
| this item |

Related

Find records WHERE substring number is less than specified number in SQL

I have a database where numbers are added in the records as substring like "NYC: 120000000", "San Fransico: 800000", "Chicago: 10000000" etc in the population column.
How can I fetch Records where a number in the substring is less than or greater than a specific number?
Like
SELECT * FROM `cities` WHERE `population` < 10000000
So I should get "San Fransico: 800000"
If the data has to be in such a format you could use substring_index as suggested in comments
select * from cities
where cast(substring_index(city_value,':',-1) as decimal) > 10000;
It looks like : is a standard delimiter in this field.
Substring_index returns a substring of a string before a specified number of delimiter occurs. In this case, the -1 parameter returns everything to the right of the : delimiter
substring_index Documentation
You can use substring_index with delimiter space starting from the end with position -1.
To sort by numerical order so that 9 comes before 10 we have to cast to integer.
As you can see it takes a lot of manipulation to extract the 2 values from the column. It would definitely be simpler and faster to have 2 separate columns.
create table cities(
city varchar(100)
);
insert into cities values
('NYC: 120000000'),
('San Fransico: 800000'),
('Chicago: 10000000');
SELECT
LEFT(
city,
CHAR_LENGTH(city)
- LOCATE(
' ',
REVERSE(city))
- 1
)
as city
,
SUBSTRING_INDEX(city,' ',-1) population
from cities
order by
cast(
substring_index(city,' ',-1)
as unsigned)
city | population
:----------- | :---------
San Fransico | 800000
Chicago | 10000000
NYC | 120000000
db<>fiddle here
If you are using MySQL 8+ you can use REGEXP_REPLACE:
select population, REGEXP_REPLACE(population, '[^0-9]+', '')
from cities
where REGEXP_REPLACE(population, '[^0-9]+', '') < 10000000;
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=0fa0a734260ec4b07c4f0bbe717e1068

How to define a custom ORDER BY in MySQL query

I need output in following order(firstly, group by last 3 letters and then arrange in order based on the first 3 digits)
ColumnA
001_eng
004_eng
002_chn
003_usa
But order by ColumnA gives me
ColumnA
001_eng
002_chn
003_usa
004_eng
This is just sample data. I have hundreds of entries in this format and the values keep changing everyday. So, specifying all the entries inside the field is not a feasible option.
I'm not sure of how to use FIELD() in my case.
You can use FIELD:
select *
from tablename
order by
FIELD(ColumnA, '001_eng', '004_eng', '002_chn', '003_usa')
(please be careful if ColumnA is not in the list the field function will return 0 and the rows will be put on top)
or you can use CASE WHEN:
select *
from tablename
order by
case
when ColumnA='001_eng' then 1
when ColumnA='004_eng' then 2
when ColumnA='002_chn' then 3
when ColumnA='003_usa' then 4
else 5
end
or you can use a different languages table where you specify the order:
id | name | sortorder
1 | 001_eng | 1
2 | 002_chn | 3
3 | 003_usa | 4
4 | 004_eng | 2
then you can use a join
select t.*
from
tablename t inner join languages l
on t.lang_id = l.id
order by
l.sortorder
(with proper indexes this would be the better solution with optimal performances)
You can use SUBSTRING_INDEX in case all ColumnA values are formatted like in the sample data:
SELECT *
FROM mytable
ORDER BY FIELD(SUBSTRING_INDEX(ColumnA, '_', -1), 'eng', 'chn', 'usa'),
SUBSTRING_INDEX(ColumnA, '_', 1)
Demo here
you can use substring() and get order by
SELECT *
FROM table_name
ORDER BY SUBSTRING(ColumnA, -7, 3);

Trying to specific values from a mysql column

I have a mysql (text)column that contains all comments with hash tags and I'm looking for a way to select only the hash tags
Id | Column
1 | I'm #cool and #calm
2 | l like #manchester
3 | #mysql troubles not #cool
You can sort of do what you want by using substring_index() to do the parsing. Assuming that the character after the hash tag is a space, you can do:
select t.*,
substring_index(substring_index(comment, '#', n.n + 1), ' ', 1)
from table t join
(select 1 as n union all select 2 union all select 3) n
on n.n <= length(t.comment) - length(replace(t.comment, '#', '')) ;
The fancy on clause is counting the number of # in the comment, which is counting the number of tags.
You can use Regular Expressions
Try this Regular Expression:
/(#[A-Za-z])\w+
Demo:
[http://regexr.com/3a2q7][1]

how can extract part of a text from a field in mysql?

I have fields like this:
-----------------
id | name
-----------------
1 | name123
-----------------
2 | name
-----------------
3 | name456
-----------------
4 | name
I want to extract rows which have digit in name and a field that contains the number like this
------------------------------
id | name | number
-----------------------------
1 | name123 | 123
-----------------------------
3 | name456 | 456
how can we find the records that have digit and extract digit as a new field?
Here is another way to do with mysql
SELECT
id,
name,
SUBSTRING(
name,LEAST (
if (Locate('0',name) >0,Locate('0',name),999),
if (Locate('1',name) >0,Locate('1',name),999),
if (Locate('2',name) >0,Locate('2',name),999),
if (Locate('3',name) >0,Locate('3',name),999),
if (Locate('4',name) >0,Locate('4',name),999),
if (Locate('5',name) >0,Locate('5',name),999),
if (Locate('6',name) >0,Locate('6',name),999),
if (Locate('7',name) >0,Locate('7',name),999),
if (Locate('8',name) >0,Locate('8',name),999),
if (Locate('9',name) >0,Locate('9',name),999)
),LENGTH(name)
) as number
from users
having number <> '' ;
you can use MySQL's string conversion on an int to strip out the name like so
SELECT
t.id,
t.name,
REVERSE(REVERSE(t.name)+ 0) AS num,
REPLACE(t.name,REVERSE(REVERSE(t.name)+ 0),'') AS actualname
FROM foobar t
HAVING num <> 0
the trick with this is by adding a 0 mysql is comparing the numeric value in the name... however the name has to start with a number... so I reverse it do the calculation and then reverse again... NOTE all of your names have to start with the name and end with a number for this to work for all of them
FIDDLE DEMO
EDIT:
since you say that some can start with a number and others end with a number.. then try this
SELECT
t.id,
t.name,
REVERSE(REVERSE(t.name)+ 0) AS num,
REPLACE(t.name,REVERSE(REVERSE(t.name)+ 0),'') AS actualname
FROM foobar t
HAVING num <> 0
UNION ALL
SELECT
t.id,
t.name,
t.name + 0 AS num,
REPLACE(t.name,t.name + 0,'') AS actualname
FROM foobar t
HAVING num <> 0
ANOTHER DEMO
Another way, assuming the number you want is at the end of the string. REVERSE() to put the number part in front, then CONVERT() to make it a number and strip off the text, then REVERSE() again WHERE name ends in a number. Feels like a kludge though:
select id, name, reverse(convert(reverse(name),signed ))
from tbl
where name REGEXP '[0-9]+$';
SQL Fiddle Example

Subquery to String?

I have a table containing countries:
id country
------------
0 Monaco
1 Mongolia
2 Montenegro
3 Morocco
4 Mozambique
5 Myanmar
I have a sub query that looks like this.
(SELECT country FROM COUNTRIES WHERE id < 10) AS ´Trip´
I want to have that subquery to be formatted as a string like this:
'Monaco, Mongolia, Montenegro, Morocco, Mozambique, Myanmar'
Is that possible?
You can use the group_concat function:
SELECT group_concat(country, ', ') FROM countries WHERE id < 10
What Lukas said, but use the SEPARATOR for your ,'s
SELECT group_concat(country SEPARATOR ', ') FROM countries WHERE id < 10
This is useful if you want a ';' instead of a ','