MySQL order varchar alpha-numerically - mysql

Given a VARCHAR column called title with the following SELECT title FROM table ORDER BY title results:
Alpha 11
Alpha 2
Beta 1
Beta 11
Beta 2
I would like this to be in the "correct" order of
Alpha 2
Alpha 11
Beta 1
Beta 2
Beta 11
Is there a way to do this?

Try this:
SELECT title ,
SUBSTRING_INDEX(title, '', 1) as title_str,
SUBSTRING_INDEX(title, ' ', -1) + 0 as title_num
FROM table
ORDER BY title_str,
title_num

This is called Natural Order sorting. Unfortunately there is no such sort algorithm built-in to MySQL, so your most reliable bet would be to create a UDF to do it for you.
However, this question has an interesting answer:
Here is a quick solution:
SELECT title
FROM table
ORDER BY LENGTH(title), title

Try this:
SELECT title
FROM tablename
ORDER BY SUBSTRING_INDEX(title, ' ', 1),
CAST(SUBSTRING_INDEX(title, ' ', -1) AS UNSIGNED);

Related

MySQL How LIKE 1 digit

I have this records:
Number
1, 2
1, 24
How to select only 2 by LIKE not 2 and 24
SELECT * FROM test WHERE number LIKE '%2%'
1, 2 // need only this record
1, 24
You should avoiding storing unnormalized CSV data like this. That being said, if you must proceed, here is one way:
SELECT *
FROM test
WHERE CONCAT(' ', number, ' ') LIKE '% 2 %';
find_in_set almost does what you want, but you'll have to remove the spaces in order to use it:
SELECT *
FROM test
WHERE FIND_IN_SET('2', REPLACE(number, ' ', '')) > 0
You can do it as follows :
SELECT `number`
FROM `test`
WHERE TRIM(SUBSTRING_INDEX(`number`, ',', -1)) = 2 or TRIM(SUBSTRING_INDEX(`number`, ',', 1)) = 2;
SUBSTRING_INDEX to split number, and TRIM to remove any space, then we search in to parts of the number.

MySQL - Sort alphabetical with numbers

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 |

Count the frequency of each word

I've been trolling the internet and realize that MySQL is not the best way to get at this but I'm asking anyway. What query, function or stored procedure has anyone seen or used that will get the frequency of a word across a text column.
ID|comment
----------------------
Ex. 1|I love this burger
2|I hate this burger
word | count
-------|-------
burger | 2
I | 2
this | 2
love | 1
hate | 1
This solution seems to do the job (stolen almost verbatim from this page). It requires an auxiliary table, filled with sequential numbers from 1 to at least the expected number of distinct words. This is quite important to check that the auxiliary table is large enough, or results will be wrong (showing no error).
SELECT
SUBSTRING_INDEX(SUBSTRING_INDEX(maintable.comment, ' ', auxiliary.id), ' ', -1) AS word,
COUNT(*) AS frequency
FROM maintable
JOIN auxiliary ON
LENGTH(comment)>0 AND SUBSTRING_INDEX(SUBSTRING_INDEX(comment, ' ', auxiliary.id), ' ', -1)
<> SUBSTRING_INDEX(SUBSTRING_INDEX(comment, ' ', auxiliary.id-1), ' ', -1)
GROUP BY word
HAVING word <> ' '
ORDER BY frequency DESC;
SQL Fiddle
This approach is as inefficient as one can be, because it cannot use any index.
As an alterative, I would use a statistics table that I would keep up-to-date with triggers. Perhaps initialise the stats table with the above.
Something like this should work. Just make sure you don't pass in a 0 length string.
SET #searchString = 'burger';
SELECT
ID,
LENGTH(comment) - LENGTH(REPLACE(comment, #searchString, '')) / LENGTH(#searchString) AS count
FROM MyTable;

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.

Spliting MySql value with default function in mysql?

I Have a sitatation like the following:
In MySql Table Entries:
img_id name
1 aa.jpg
2 aab.mpeg
3 aabc.jpg
4 aabd.jpg
5 aabn.jpg
6 aabf.jpg
7 aadf.jpg
8 aacf.jpg
I want the count after splitting thew above values........
like
".jpg"=>7
".mpeg"=>1
SELECT RIGHT(Name, LOCATE('.', REVERSE(Name)) - 1) Format,
COUNT(*) TotalCOunt
FROM TableName
GROUP BY RIGHT(Name, LOCATE('.', REVERSE(Name)) - 1)
SQLFiddle Demo
Consider normalizing the table. In the long run, this will perform slow.