How to order by a text column that contains int in SQL? - sql

My current SQl statement is:
SELECT distinct [Position] FROM [Drive List] ORDER BY [Position]ASC
And the output is ordered as seen below:
1_A_0_0_0_0_0
1_A_0_0_0_0_1
1_A_0_0_0_0_10
1_A_0_0_0_0_11
1_A_0_0_0_0_12
1_A_0_0_0_0_13 - 1_A_0_0_0_0_24, and then 0_2-0_9
The field type is Text in a Microsoft Access Database. Why is the order jumbled and is there any way of correctly sorting the values?

"Why the order is jumbled":
The order is only jumbled because you are compiling it with your human brain and are applying more value than the computer does because of your symbolic understand of what the values represent. Parse the output as though you could only understand it as an array of character strings, and you were trying to determine which string is the greatest, all the while knowing nothing about the symbolic value of each character. You will find that the output your query generated is perfectly logical and not at all jumbled.
"Any way of correctly sorting the values"
This is a design issue and it should be addressed if it really is a problem.
Change 1_A_0_0_0_0_0 to 1_A_0_0_0_0_00
Change 1_A_0_0_0_0_1 to 1_A_0_0_0_0_01
Change 1_A_0_0_0_0_2 to 1_A_0_0_0_0_02
etc
This will make the problem go away.
Use these two separate queries:
SELECT distinct [Position] FROM [Drive List] WHERE [Position] LIKE '1_A_0_0_0_0_?' ORDER BY [Position] ASC
SELECT distinct [Position] FROM [Drive List] WHERE [Position] LIKE '1_A_0_0_0_0_??' ORDER BY [Position] ASC
...add to a temp table and append to get the results to display properly.

If you want sorting which incorporates the numerical values of those substrings, you can cast them to numbers.
In the simplest case, you're concerned with only the digit(s) after the 12th character. That case would be fairly easy.
SELECT
sub.Position,
Left(sub.Position, 12) AS sort_1,
Val(Mid(sub.Position, 13)) AS sort_2
FROM
(
SELECT DISTINCT [Position] FROM [Drive List]
) AS sub
ORDER BY 2, 3;
Or if you want to display only the Position field, you could do it this way ...
SELECT
sub.Position
FROM
(
SELECT DISTINCT [Position] FROM [Drive List]
) AS sub
ORDER BY
Left(sub.Position, 12),
Val(Mid(sub.Position, 13));
However, your actual situation could be much more challenging ... perhaps the initial substring (everything up to and including the final _ character) is not consistently 12 characters long, and/or includes digits which you also want sorted numerically. You could then use a mix of InStr(), Mid(),and Val() expressions to parse out the values to sort. But that task could get scary bad real fast! It could be less effort to alter the stored values so they sort correctly in character order as #Justin suggested.

Your jumbled order is caused because it is a text field. As for solutions you could attempt to add an additional column in your table that is numeric and order by that instead of Position. I would need more information about what data you have and what it means to suggest a good way to do this.

This is the right sort for a string.
In alphabetical order 10 come before 2.
For orderby the last number you can try with SUBSTRING and CAST (or CONVERT) commands

Related

Natural or Human Sort order

I have been working on this on for months. I just cannot get the natural (True alpha-numeric) results. I am shocked that I cannot get them as I have been able to in RPG since 1992 with EBCDIC.
I am looking for any solution in SQL, VBS or simple excel or access. Here is the data I have:
299-8,
3410L-87,
3410L-88,
420-A20,
420-A21,
420A-40,
4357-3,
AN3H10A,
K117GM-8,
K129-1,
K129-15,
K271B-200L,
K271B-38L,
K271D-200EL,
KD1051,
KD1062,
KD1092,
KD1108,
KD1108,
M8000-3,
MS24665-1,
SK271B-200L,
SAYA4008
The order I am looking for is the true alpha-numeric order as below:
AN3H10A,
KD1051,
KD1062,
KD1092,
KD1108,
KD1108,
K117GM-8,
K129-1,
K129-15,
MS24665-1,
M8000-3,
SAYA4008,
SK271B-200L
The inventory is 7800 records so I have had some problems with processing power as well.
Any help would be appreciated.
Jeff
In native Excel, you can add multiple sorting columns to return the ASCII code for each character, but if the character is a number, then add a large number to the code (e.g 1000).
Then sort on each of the helper columns, including the first column in the table, but not in the sort.
The formula:
=IFERROR(CODE(MID($A1,COLUMNS($A:A),1))+AND(CODE(MID($A1,COLUMNS($A:A),1))>=48,CODE(MID($A1,COLUMNS($A:A),1))<=57)*1000,"")
The Sort dialog:
The results:
You can implement a similar algorithm using VBA, and probably SQL also. I dunno about VBS or Access.
You could try using format for left padding the string in order by
select column
from my_table
order by Format(column, "0000000000")
Add a sorting column:
, iif (left(fieldname, 1) between '0' and '9', 1, 0) sortField
etc
order by sortField, FieldName
Lets say you have your data in column "A". If you put this formula in column "B" =IFERROR(IF(LEFT(A1,1)+1>0,"ZZZZZZZ "&A1,A1),A1), it will automatically add Z in front of all numerical values, so that they will naturally appear after all alphabetical values when you sort A-Z. later you can find&replace that funny ZZZZZZ string...
There a number of approaches, but likely the least amount of work is to build two columns that split out the delimiter (-) in this case.
You then “pad” the results (spaces, or 0) right justified, and then sort on the two columns.
So in the query builder we have this:
SELECT Field1,
Format(
Mid(field1,1,IIf(InStr(field1,"-")=0,50,InStr(field1,"-")-1)),
">##########") AS Expr1,
Format(
Mid(field1,IIf(InStr(field1,"-")=0,99,InStr(field1,"-")+1)),
">##########") AS Expr2
FROM Data
When we run the above raw query we get this:
So now in the query builder, simply sort on the first derived column, and then sort on the 2nd derived column.
Eg this:
Run the query, and we get this result:
Edit:
Looking at you desired results, it looks like above sort is wrong. We have to RIGHT just and pad with 0’s.
So this 2nd try:
SELECT Field1,
Left(Mid(field1,1,IIf(InStr(field1,"-")=0,30,InStr(field1,"-")-1))
& String(30,"0"),30) AS Expr1,
Left(Mid(field1,IIf(InStr(field1,"-")=0,99,InStr(field1,"-")+1))
& String(30,"0"),30) AS Expr2
FROM Data
The results are thus this:
Given your small table size, then the above query should perform quite well.

Return rows where first character is non-alpha

I'm trying to retrieve all columns that start with any non alpha characters in SQlite but can't seem to get it working. I've currently got this code, but it returns every row:
SELECT * FROM TestTable WHERE TestNames NOT LIKE '[A-z]%'
Is there a way to retrieve all rows where the first character of TestNames are not part of the alphabet?
Are you going first character only?
select * from TestTable WHERE substr(TestNames,1) NOT LIKE '%[^a-zA-Z]%'
The substr function (can also be called as left() in some SQL languages) will help isolate the first char in the string for you.
edit:
Maybe substr(TestNames,1,1) in sqllite, I don't have a ready instance to test the syntax there on.
Added:
select * from TestTable WHERE Upper(substr(TestNames,1,1)) NOT in ('A','B','C','D','E',....)
Doesn't seem optimal, but functionally will work. Unsure what char commands there are to do a range of letters in SQLlite.
I used 'upper' to make it so you don't need to do lower case letters in the not in statement...kinda hope SQLlite knows what that is.
try
SELECT * FROM TestTable WHERE TestNames NOT LIKE '[^a-zA-Z]%'
SELECT * FROM NC_CRIT_ATTACH WHERE substring(FILENAME,1,1) NOT LIKE '[A-z]%';
SHOULD be a little faster as it is
A) First getting all of the data from the first column only, then scanning it.
B) Still a full-table scan unless you index this column.

Sorting data in Access database where the column has numbers and letters

Please help me because I have been unable to get this right.
What is the access SQL to select this column(columnA) so that it returns a resultset with distinct values sorted first according to numbers and then to letters.
Here is the columns values: {10A,9C,12D,11G,9B,10C,9R,8T}
I have tried 'Select distinct ColumnA from tblClass order by 1'
but it returns {10A,10C,11G,12D,8T,9B,9C,9R} which is not what I want.
Thank you in advance.
You can use the Val() function for this. From the help topic: "The Val function stops reading the string at the first character it can't recognize as part of a number"
Val(10A) will give you 10, Val(9C) will give you 9, and so on. So in your query, order by Val(ColumnA) first, then ColumnA.
SELECT DISTINCT Val([ColumnA]) AS number_part, ColumnA
FROM tblClass
ORDER BY Val([ColumnA]), ColumnA;
SELECT DISTINCT ColumnA
FROM tblClass
ORDER BY CInt(LEFT(ColumnA,len(ColumnA)-1)), RIGHT(ColumnA,1);
If there last character is a letter and the others are a number.
Your data type is a string so it's sorting correctly, to get the result you want you're going to have to split your values into numeric and alphabetic parts and then sort first on the numeric then the alphabetic. Not being an Access programmer I can't help you with exactly how you're going to do that.
order by 1?
Don't you mean order by ColumnA?
SELECT DISTINCT ColumnA
FROM tblClass
ORDER BY ColumnA
I had a similar problem and used a dummie workaround:
changing a list of {10A,10C,11G,12D,8T,9B,9C,9R}
into {10A,10C,11G,12D,08T,09B,09C,09R} by adding the 0 before each <10 number.
now all items are the same length and access will sort correctly into {08T, 09B, 09C, 09R, 10A, 10C, 11G, 12D}
.
To achieve this, I copied this column into excel column A and used IF(LEN(A2)<3, concatenate("0", A2))

How do I sort a VARCHAR column in PostgreSQL that contains words and numbers?

I need to order a select query using a varchar column, using numerical and text order. The query will be done in a java program, using jdbc over postgresql.
If I use ORDER BY in the select clause I obtain:
1
11
2
abc
However, I need to obtain:
1
2
11
abc
The problem is that the column can also contain text.
This question is similar (but targeted for SQL Server):
How do I sort a VARCHAR column in SQL server that contains words and numbers?
However, the solution proposed did not work with PostgreSQL.
Thanks in advance, regards,
I had the same problem and the following code solves it:
SELECT ...
FROM table
order by
CASE WHEN column < 'A'
THEN lpad(column, size, '0')
ELSE column
END;
The size var is the length of the varchar column, e.g 255 for varying(255).
You can use regular expression to do this kind of thing:
select THECOL from ...
order by
case
when substring(THECOL from '^\d+$') is null then 9999
else cast(THECOL as integer)
end,
THECOL
First you use regular expression to detect whether the content of the column is a number or not. In this case I use '^\d+$' but you can modify it to suit the situation.
If the regexp doesn't match, return a big number so this row will fall to the bottom of the order.
If the regexp matches, convert the string to number and then sort on that.
After this, sort regularly with the column.
I'm not aware of any database having a "natural sort", like some know to exist in PHP. All I've found is various functions:
Natural order sort in Postgres
Comment in the PostgreSQL ORDER BY documentation

How to use ORDER BY with proper handling of numbers?

I want to get data from mysql table sorted by one of it's varchar column. So let's say I have query like this:
SELECT name, model FROM vehicle ORDER BY model
The problem is, that for 'model' values like these: 'S 43', 'S 111' the order will be:
S 111
S 43
because I suppose ORDER BY uses alphabetic order rules, right? So how to modify this query to get "numerical" order? In which 'S 43' would be before 'S 111'? Without changing or adding any data to this table.
Something like this:
SELECT name, model
FROM vehicle
ORDER BY CAST(TRIM(LEADING 'S ' FROM model) AS INTEGER)
Note, that it's not a good practice to sort by function result, because it produces dynamic unindexed result which can be very slow, especially on large datasets.
If the non-numeric portion's of constant length, you could
ORDER BY substring(model, <length of non-numeric portion>)
or, if the non-numeric portion's length varies, you could
ORDER BY substring(model, 1 + LOCATE(' ', model))
You can take numeric part only (substring functions) and convert it into int (cast functions).
mySQL cast functions
mySQL string functions
I didn't test it myself but I suppose it should work.