Natural sorting in SQL does not work - mysql

I am trying to sort a row "naturally" in SQL, and I found this answer which supposedly does exactly what I need:
https://stackoverflow.com/a/17354420/7563153
But when I tried recreating it in "SQL Fiddle" I couldn't get it to work...
Here's my attempt
What am I doing wrong?

The difference between the example you cite and your own trial, is that your data combines numeric and non-numeric characters in the same field, so casting to an integer doesn't work (it just gives 0). You can visualize why the query isn't working for you by adding the order by expressions in your select list like this:
SELECT test
,test REGEXP '^[A-Za-z]+$'
,CAST(test as SIGNED INTEGER)
,CAST(REPLACE(test,'-','')AS SIGNED INTEGER)
FROM table1
ORDER BY test REGEXP '^[A-Za-z]+$'
,CAST(test as SIGNED INTEGER)
,CAST(REPLACE(test,'-','')AS SIGNED INTEGER)
,test
You'll see that they all evaluate to 0, which does not give you the sort order you're looking for.
You need to separate the numeric portion of your value from the non-numeric portion, and sort them separately. Something like this:
SELECT test
FROM table1
ORDER BY substring_index(test,'-',1)
,CAST(substring(test, locate('-', test)+1)AS SIGNED INTEGER)
,test
You might need to adjust that if your actual data isn't as simple and straightforward as your example data.

For your given database schema, is your attempt even necessary?
Try something like this,
SELECT `test`
FROM table1
ORDER BY LENGTH(`test`),
`test`;

Assuming (!) that your data have the format "blabla-integer" with one and only one dash (-) separating the alphanumeric part from the integer part I would go this way:
select * from table1
order by cast(substring(test,
locate('-', test) + 1,
length(test) - locate('-', test)
) as signed integer
);

Related

How to find variable pattern in MySql with Regex?

I am trying to pull a product code from a long set of string formatted like a URL address. The pattern is always 3 letters followed by 3 or 4 numbers (ex. ???### or ???####). I have tried using REGEXP and LIKE syntax, but my results are off for both/I am not sure which operators to use.
The first select statement is close to trimming the URL to show just the code, but oftentimes will show a random string of numbers it may find in the URL string.
The second select statement is more rudimentary, but I am unsure which operators to use.
Which would be the quickest solution?
SELECT columnName, SUBSTR(columnName, LOCATE(columnName REGEXP "[^=\-][a-zA-Z]{3}[\d]{3,4}", columnName), LENGTH(columnName) - LOCATE(columnName REGEXP "[^=\-][a-zA-Z]{3}[\d]{3,4}", REVERSE(columnName))) AS extractedData FROM tableName
SELECT columnName FROM tableName WHERE columnName LIKE '%___###%' OR columnName LIKE '%___####%'
-- Will take a substring of this result as well
Example Data:
randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-xyz123&hello_world=us&etc_etc
In this case, the desired string is "xyz123" and the location of said pattern is variable based on each entry.
EDIT
SELECT column, LOCATE(column REGEXP "([a-zA-Z]{3}[0-9]{3,4}$)", column), SUBSTR(column, LOCATE(column REGEXP "([a-zA-Z]{3}[0-9]{3,4}$)", column), LENGTH(column) - LOCATE(column REGEXP "^.*[a-zA-Z]{3}[0-9]{3,4}", REVERSE(column))) AS extractData From mainTable
This expression is still not grabbing the right data, but I feel like it may get me closer.
I suggest using
REGEXP_SUBSTR(column, '(?<=[&?]random_code=[^&#]{0,256}-)[a-zA-Z]{3}[0-9]{3,4}(?![^&#])')
Details:
(?<=[&?]random_code=[^&#]{0,256}-) - immediately on the left, there must be & or &, random_code=, and then zero to 256 chars other than & and # followed with a - char
[a-zA-Z]{3} - three ASCII letters
[0-9]{3,4} - three to four ASCII digits
(?![^&#]) - that are followed either with &, # or end of string.
See the online demo:
WITH cte AS ( SELECT 'randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-xyz123&hello_world=us&etc_etc' val
UNION ALL
SELECT 'randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-xyz4567&hello_world=us&etc_etc'
UNION ALL
SELECT 'randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-xyz89&hello_world=us&etc_etc'
UNION ALL
SELECT 'randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-xyz00000&hello_world=us&etc_etc'
UNION ALL
SELECT 'randomwebsite.com/3982356923abcd1ab?random_code=12480712_ABC_DEF_ANOTHER_CODE-aaaaa11111&hello_world=us&etc_etc')
SELECT REGEXP_SUBSTR(val,'(?<=[&?]random_code=[^&#]{0,256}-)[a-zA-Z]{3}[0-9]{3,4}(?![^&#])') output
FROM cte
Output:
I'd make use of capture groups:
(?<=[=\-\\])([a-zA-Z]{3}[\d]{3,4})(?=[&])
I assume with [^=\-] you wanted to capture string with "-","\" or "=" in front but not include those chars in the result. To do that use "positive lookbehind" (?<=.
I also added a lookahead (?= for "&".
If you'd like to fidget more with regex I recommend RegExr

How to select everything that does not start with s number in MySQL

I am trying to find all values that do not start with a number
I have tried this query, but not sure if the REGEXP is correct. This seem to be returning any value the does not contains a number
SELECT * FROM table where address NOT REGEXP '[0-9]'
I think this fixed the issue
SELECT * FROM table where address NOT REGEXP '^[0-9]'
In MySQL if you try to convert a string to a number then it will start from the beginning taking the digits and convert as much as possible.
If a string does not start with a number then the result is 0.
select * from your_table
where address * 1 = 0
SQLFiddle demo
You can use explicit conversion with cast(str_column as unsigned) or implicit conversion by using a mathematical operator like * 1

Mysql, how to order by the first number in a set of numbers

I need to order by a field that contains a set of numbers. Lets say a table named TEST contains ID, NAME, QUADS with QUADS as follows.
95,273,212,405
717,450,771,504
391,176,646,272
This are the results I am getting with a query such as
SELECT * FROM TEST ORDER BY QUADS
391,176,646,272
717,450,771,504
95,273,212,405
These are the results I am looking to get
95,273,212,405
391,176,646,272
717,450,771,504
I am only interested in the first number in the set for "order". Figure it might be possible with a substring to the comma but not sure how to do that in MySQL.
Try this:
select * from test
order by cast(substring_index(quads,',',1) as unsigned)
What you want is the substring_index function.
... order by substring_index(x_field,',',1)
This extracts the text in x_field up to the first occurrence of the comma delimiter
Try with this:
select QUADS, 0+QUADS as S from TEST order by S
0+QUADS will convert your string to int and will use for it just the first digits sequence before "," which is actually what you want.

Why does this search query return nothing?

I have this table under user_name='high'
function_description :
akram is in a date
test
akram is studying
test4
kheith is male
test3
I want a query that returns results of field that have at least an 'akram'
SELECT *
FROM functions
WHERE 'isEnabled'=1
AND 'isPrivate'=1
AND user_name='high'
AND function_description LIKE '%akram%'
and this returns absolutely nothing!
Why?
You are listing the column names as if they are strings. This is why it returns nothing.
Try this:
SELECT *
FROM functions
WHERE user_name='high'
AND function_description LIKE '%akram%'
edit: After trying to re-read your question... are isEnabled and isPrivate columns in this table?
edit2: updated.. remove those unknown columns.
You are comparing strings 'isEnabled' with integer 1, which likely leads to the integer being converted to a string, and the comparison then fails. (The alternative is that the string is converted to an integer 0 and the comparison still fails.)
In MySQL, you use back-quotes, not single quotes, to quote column and table names:
SELECT *
FROM `functions`
WHERE `isEnabled` = 1
AND `isPrivate` = 1
AND `user_name` = 'high'
AND `function_description` LIKE '%akram%'
In standard SQL, you use double quotes to create a 'delimited identifier'; in Microsoft SQL Server, you use square brackets around the names.
Please show the schema more carefully (column names, sample values, types if need be) next time.

MySQL SELECT WHERE 'a' IN (`field`)

I know it is not an appropriate technique to have a structure of MySQL table as such, but I have to work with such. The problem is, that the field in table has value with comma seperated integers, like "1,3,5,7,10" and I want the query to return rows, in which field has a to the query passed number in it, like:
SELECT * FROM `table` WHERE '5' IN (`field_in_table`)
However, it does not work, if, in this case, '5' is not the first number in the field.
Any advises, how to solve that?
Thanks in advance,
Regards,
Jonas
Have a look at
FIND_IN_SET
Returns a value in the range of 1 to N
if the string str is in the string
list strlist consisting of N
substrings. A string list is a string
composed of substrings separated by
“,” characters. If the first argument
is a constant string and the second is
a column of type SET, the
FIND_IN_SET() function is optimized to
use bit arithmetic. Returns 0 if str
is not in strlist or if strlist is the
empty string.
You could use WHERE field_in_table LIKE '%5%' instead.
Of course, the problem would be, '1,59,98' would return as wel.
SELECT * FROM table WHERE field_in_table LIKE '%5'");
should work
You could try
SELECT *
FROM table
WHERE '%,5,%' LIKE field_in_table OR
'%,5' LIKE field_in_table OR
'5,%' LIKE field_in_table;
A better approach might be to use regular expressions, a subject on which I am not an authority.
SELECT *
FROM table
WHERE FIELD LIKE '%,5,%' OR
FIELD LIKE '5,%' OR
FIELD LIKE '%,5'