Sort Numeric & Alphanumeric Accordingly in PHP MySQL - mysql

I am using a Query which sorts like;
1
2
3A
3
4A
4
But I want to get it
1
2
3
3A
4
4A
What I am using is
SELECT * FROM `sections` ORDER BY CAST(`act` as DECIMAL) ASC
What I exactly want is First Number then Alphanumeric
3 then 3A

Considering that you'll always have integer first and then characters in your acts column. Normally this is called Natural Sorting.
Problem Understanding:
Normal sorting works perfectly when we're dealing with variations of a single number i.e. 1, 1A, 1B, 1AB...
Due to string type, it fails when we sort between numbers which starts with same digit like 1, 10, 100....
We can sort in following manner.
First sort them based on their integer values.
Then sort them normally which mysql takes care by default.
SELECT * FROM sections
ORDER BY CAST(acts AS UNSIGNED), acts
Check corresponding fiddle. It is working for MySQL 5.5, 5.6, 5.7 & 8.0.

Related

MySQL - Convert single column into an array

I have a column of data, e.g. as follows:
select league_id from leagues
This gives me a single column (league_id) and 100+ rows for that column.
I want to convert it into a single cell (1 row, 1 column) with the following structure:
[1001, 1002, 42022, 203412, 24252, etc..]
Essentially converting the rows into one big array.
There must be a way of doing it but can't see how.
I'm using MariaDB 10.2.
You can use the GROUP_CONCAT() function for that.
Usage is straightforward:
id
val
1
1001
2
1002
3
42022
4
203412
5
24252
SELECT group_concat(val)
FROM tab
gives you
group_concat(val)
1001,1002,42022,203412,24252
See db<>fiddle.
(Note: Before MariaDB 10.3.3 you cannot use the LIMIT clause with GROUP_CONCAT, in case you should need that).

Is there a possibility to change the order of a string with numeric value

I have some strings in my database. Some of them have numeric values (but in string format of course). I am displaying those values ordered ascending.
So we know, for string values, 10 is greater than 2 for example, which is normal. I am asking if there is any solution to display 10 after 2, without changing the code or the database structure, only the data.
If for example I have to display values from 1 to 10, I will have:
1
10
2
3
4
5
6
7
8
9
What I would like to have is
1
2
3
4
5
6
7
8
9
10
Is there a possibility to ad an "invisible character or string which will be interpreted as greater than 9". If i put a10 instead of 10, the a10 will be at the end but is there any invisible or less visible character for that.
So, I repeat, I am not looking for a programming or database structure solution, but for a simple workaround.
You could try to cast the value as an number to then order by it:
select col
from yourtable
order by cast(col AS UNSIGNED)
See SQL Fiddle with demo
You could try appending the correct number of zeroes to the front of the data:
01
02
03
..
10
11
..
99
Since you have a mixture of numbers and letters in this column - even if not in a single row - what you're really trying to do is a Natural Sort. This is not something MySQL can do natively. There are some work arounds, however. The best I've come across are:
Sort by length then value.
SELECT
mixedColumn
FROM
tableName
ORDER BY
LENGTH(mixedColumn), mixedColumn;
For more examples see: http://www.copterlabs.com/blog/natural-sorting-in-mysql/
Use a secondary column to use as a sort key that would contain some sort of normalized data (i.e. only numbers or only letters).
CREATE TABLE tableName (mixedColumn varchar, sortColumn int);
INSERT INTO tableName VALUES ('1',1), ('2',2), ('10',3),
('a',4),('a1',5),('a2',6),('b1',7);
SELECT
mixedColumn
FROM
tableName
ORDER BY
sortColumn;
This could get difficult to maintain unless you can figure out a good way to handle the ordering.
Of course if you were able to go outside of the database you'd be able to use natural sort functions from various programming languages.

sorting numbers stored in text field in MYSQL database

i have a mySQL database with a text field in which is stored a number.
i need to produce a recordset sorted in descending numerical order.
this works fine until we get to numbers greater than 10 ie
9
8
7
6
5
4
3
2
10
1
is there a simple way of sorting this 'correctly' ?
(yes, i know i should have numbers in a numerical field, but i'm working with what i have :))
i'm using the results on an asp/vbscript/jquery page so maybe even a client-side solution is viable...
any suggestions?
ORDER BY ABS(text_column) DESC
Or, if you also have to deal with negative values:
ORDER BY CAST(text_column AS SIGNED) DESC
You need to type cast it to INTEGER using CAST function in MySQL:
ORDER BY CAST(text_column AS UNSIGNED INTEGER)
Try this one -
... ORDER BY text_column * 1

Grade Up/Down APL order

How come that
⌽(⍒'Hello')
is
1 2 4 3 5
when
⍋'Hello'
is
1 2 3 4 5
?
I'm new to APL and stumbled on it by accident. I just wonderes why the second l comes before the first.
You are using both the grade up ⍋ and grade down ⍒ as monadic primitives.
By definition grade up returns an integer array of indices which specify the sorted order of the expression following it, in ascending order. If any elements are equal (in your example the two letter l's) , they will appear in the result in the same order that they appeared in the input expression.
So, ⍋'Hello' returns 1 2 3 4 5. The two l's are in the same order, i.e., the 3rd character (1st letter l) precedes the 4th character (2nd letter l).
By definition grade down also returns an integer array of indices which specify the sorted order of the expression following it, in descending order. If any elements are equal (in your example the two letter l's) , they will also appear in the result in the same order that they appeared in the expression.
So, ⍒'Hello' returns 5 3 4 2 1. The two l's remain in the same order because they are equal.
When you apply rotate ⌽ the integer array gets reversed to 1 2 4 3 5 as you witnessed.
The outcome you are seeing is precisely what is expected given the way the functions are defined and how they deal with equal values.
If you want to see a more extreme example compare the output for the following two arrays. Create an array with 10 elements each having the same value of 1. 10⍴1 and then try the grade up function and then try the grade down function:
⍋10⍴1
and
⍒10⍴1
They will both yield the same result:
1 2 3 4 5 6 7 8 9 10
The grade up ⍋ and grade down ⍒ primitives preserve the order of equal elements. As others have said, there must be a rule for equal arguments. But this rule has the virtue that it allows multi-key sorts.
That is, if you have an array with several associated keys, by sorting on each key from least significant to most significant, you obtain a result sorted by the most significant key, with equals sorted by the 2nd mot significant, items equal on the 1st two sorted by the 3rd, and so on. For this to work the index vector must be captured and used to update all keys and the data to keep them in sync. Or they could be stored in a nested structure, in which case they would automatically be kept in proper relative order.

Need MySQL Query to Chop String and add Serial Number (letter) to End, Where Duplicates

Let's say we have some 10 character skus like this:
AB1234ZYXW
AB1234ZYXN
AB1234ZYXP
AB1234ZYXR
ZZ1234ZYXR
But we need them to be 8 characters. Chopping them at 8 would make them non unique (except the last one).
The non-unique ones would all look like : AB1234ZY
So my solution is to chop one more character off of all them, giving AB1234Z, then adding a serial number (actually serial letter). AB1234ZA, AB1234ZB, ...C ...D.
My first thought was to query the DB and do all the processing in PHP arrays, then send queries back to update. But since there can be 30,000 to process at a time, this will result in 30,000 UPDATE queries (one for each chopped sku anyway).
If it could be done with a single MySQL statement it would be much faster.
Any ideas?
EDIT:
To add more detail:
Total number of records could be 2,000 - 35,000 per batch. With the chopping, it will create groups of duplicates. If each group has less than 26 members, then 1 digit of serialization is enough. Otherwise 2 digits (26 x 26 = 676 and it's very unlikely a group would be larger than that). Ideally, the query would take into account the number of duplicates in each group and apply 1 or 2 digits of serialization depending. I know it's a lot to ask. jonstjohn's answer looks like a good start. I will test it tomorrow. I haven't used mysql variables for anything yet but it looks promising.
Try the following:
SET #num = 64;
UPDATE skus SET sku = concat(left(sku, 7),
char(if((#num := #num + 1) <= 90, #num, #num := 65)));
Here's the explanation.
The first line assigns the integer 64 to the mysql variable #num. The character code for 'A' is 65 and 'Z' is 90, so we assign one before the 'A' since it will be incremented in the update query.
The update query then updates each row of the skus table using the first 7 characters of the sku, plus an incrementing character (A-Z) using the #num variable. When it hits 'Z', it resets itselft to 65 (and uses that value for that row).
It should be very fast and efficient.