Non-standard sort order - sql

I have the following data in an SQL column. Column type is String. I would prefer to sort this data when I query it from the DB, but I suppose it could be organized with some Ruby magic after the SQL query is complete. There are other columns being pulled out, so this is just one of the columns that needs to be sorted.
Expenses
$3500/MONTH
$1,000.00
STANDARD CONTRACTOR
$5,000.00
The data cannot change and must be stored in the same column (the example above just test data).
I would like to organize the data by increasing number and then the rest (string) values. The expected result should be:
$1,000.00
$5,000.00
$3500/MONTH
STANDARD CONTRACTOR
or
$1,000.00
$5,000.00
STANDARD CONTRACTOR
$3500/MONTH

Option 1 (fiddle here):
select expenses from table1
order by
replace(replace(expenses, "$", ""), ",", "") regexp "[0-9.]*" desc,
case when replace(replace(expenses, "$", ""), ",", "") regexp "[0-9.]*"
then cast(replace(replace(expenses, "$", ""), ",", "") as real)
else 0
end
Option 2 (fiddle here):
select expenses from (
select expenses,
replace(replace(expenses, "$", ""), ",", "") expensesNormalized
from table1
) s
order by
expensesNormalized regexp "[0-9.]*" desc,
case when expensesNormalized regexp "[0-9.]*"
then cast(expensesNormalized as real)
else 0
end
Go for whichever runs faster.

If the existing answers work in SQLlite, then perhaps they'll work for you. Because the data is pretty ... messy ... I would tend to try to encapsulate the ugly part of this in a single method that returns a sorted array.
If you have a small number of rows like this (e.g. less than 500) then the cleaner way to sort would be to include Comparable and write a custom comparator, as nicely documented in this SO answer.

In SQL Server, you can do something like the following:
order by (case when isnumeric(col) = 1 then 1 else 0 end) desc,
(case when isnumeric(col) = 1 then cast(col as money) end),
col
For other databases, you can use regular expression matching rather than isnumeric to determine which are numbers.
Since you are using SQLite and I seem to be able to assume that all the numbers start with a '$', then something like this almost works:
order by (case when substr(col, 1, 1) = '$' then 1 else 0 end) desc,
(case when substr(col, 1, 1) = '$' then cast(col as numeric) end),
col
The problem is that "$3,500/month" is treated as a number. You can fix this with a regexp, if you have that included. Or, if the "/" defines these cases, you can use something specific like:
order by (case when substr(col, 1, 1) = '$' and col not like '%/%' then 1 else 0 end) desc,
(case when substr(col, 1, 1) = '$' and col not like '%/%' then cast(col as numeric) end),
col

Related

SQL query to sort data while insert , first numbers then alphabets an last symbols

I am getting trouble to write SQL sort Query,
I have table as follows
And I want to sort above data as, First should number and then alphabets and last special symbols like following table.
First numbers should sort like 1,2,3,11,22,33
then Alphabets should sort like a ,b,c,..z
and then symbols,
like following table
I have tried many ways but still not getting correct way, please help me to write query.
You can use a CASE WHEN on the ORDER BY to create some groups:
SELECT *
FROM table_name
ORDER BY
CASE WHEN LEFT(FilterParameterValue, 1) LIKE '[0-9]' OR LEFT(FilterParameterValue, 2) LIKE '-[0-9]' OR LEFT(FilterParameterValue, 2) LIKE '+[0-9]' THEN 1 ELSE 0 END DESC, -- group for numbers
CASE WHEN ISNUMERIC(FilterParameterValue) = 1 THEN CAST(FilterParameterValue AS MONEY) ELSE NULL END ASC, -- order the numeric values
CASE WHEN LEFT(FilterParameterValue, 1) LIKE '[A-Za-z]' THEN 1 ELSE 0 END DESC, -- group for chars from A to Z (capital / non capital)
colName
demo on dbfiddle.uk
Try using regex in order by clause.. For ex
ORDER BY IF(FilterParameterValue RLIKE '^[a-z]', 1, 2), FilterParameterValue
You can try to cast your Column to Numeric Type then ordered
SELECT * FROM table_name ORDER BY TRY_CAST(Column_Name as Type)

ORDER BY Alphanumeric sort

I want to ORDER BY data in the following sequence:
Number-Number
Alpha-Number
Alpha with no dash
I have the following sort:
120-1
120-2
120-10
Digital-1
Digital-10
Digital-2
Wedding
This is the order I'm looking for, except the Digital (Alpha with dash) entries are not sorted by numbers after the dash.
After many attempts, here's my current sql statement:
SELECT SessionID, Identifier FROM Session
ORDER BY
CASE
WHEN CAST(Identifier AS INTEGER) THEN SUBSTR(Identifier,0, INSTR(Identifier, '-')) + CAST(SUBSTR(Identifier, INSTR(Identifier, '-')+1, 999) AS INTEGER)
ELSE Identifier END
What am I doing wrong?
Thanks.
1) Order by strings having - in them so they appear first
2) Order by the first part before - in the strings containing - casting them as integers where applicable, Else order by the column itself
3) Order by the second part after - in the strings containing - casting them as integers where applicable, Else order by the column itself
select val
from t
order by
case when val like '%-%' then 1 else 2 end
,case when substr(val,1,instr(val,'-')-1) glob '*[0-9]*'
then cast(substr(val,1,instr(val,'-')-1) as integer)
when substr(val,1,instr(val,'-')-1) glob '*[a-zA-Z]*'
then substr(val,1,instr(val,'-')-1)
else val end
,case when val like '%-%' then cast(substr(val,instr(val,'-')+1) as integer)
else val end
SQL Fiddle
Your logic is somehow reconstructing the strings, but for the order by, you want something like this:
order by (case when CAST(Identifier AS INTEGER) <> 0 then 1
when Identifier like '%-%' then 2
else 3
end),
identifier
Note: This assumes that the numbers are never 0.

SQL query: convert

I'm trying to read a column from a database using a SQL query. The column consists of empty string or numbers as strings, such as
"7500" "4460" "" "2900" "2640" "1850" "" "2570" "9050" "8000" "9600"
I'm trying to find the right sql query to extract all the numbers (as integers) and removing the empty ones, but I'm stuck. So far I've got
SELECT *
FROM base
WHERE CONVERT(INT, code) IS NOT NULL
Done in program R (package sqldf)
If all columns are valid integers, you could use:
select * , cast(code as int) IntCode
from base
where code <> ''
To prevent cases when field code is not a valid number, use:
select *, cast(codeN as int) IntCode
from base
cross apply (select case when code <> '' and not code like '%[^0-9]%' then code else NULL end) N(codeN)
where codeN is not null
SQL Fiddle
UPDATE
To find rows where code is not a valid number, use
select * from base where code like '%[^0-9]%'
select *
from base
where col like '[1-9]%'
Example: http://sqlfiddle.com/#!6/f7626/2/0
If you don't need to test for the number being valid, ie. a string such as '909XY2' then this may run marginally faster, more or less depending on the size of the table
Is this what you want?
SELECT (case when code not like '%[^0-9]%' then cast(code as int) end)
FROM base
WHERE code <> '' and code not like '%[^0-9]%';
The conditions are repeated in the where and case on purpose. SQL Server does not guarantee that where filters are applied before logic in the select, so you can get an error with conversions. More recent versions of SQL Server have try_convert() to fix this problem.
Using sqldf with the default sqlite database and this test data:
DF <- data.frame(a = c("7500", "4460", "", "2900", "2640", "1850", "", "2570",
"9050", "8000", "9600"), stringsAsFactors = FALSE)
try this:
library(sqldf)
sqldf("select cast(a as aint) as aint from DF where length(a) > 0")
giving:
aint
1 7500
2 4460
3 2900
4 2640
5 1850
6 2570
7 9050
8 8000
9 9600
Note In plain R one could write:
transform(subset(DF, nchar(a) > 0), a = as.integer(a))

How to quickly compare many strings?

In SQL Server, I have a string column that contains numbers. Each entry I need is only one number so no parsing is needed. I need some way to find all rows that contain numbers from 400 to 450. Instead of doing:
...where my stringcolumn like '%400%' or stringcolumn like '%401%' or stringcolumn like '%402%' or ...
is there a better that can save on some typing?
There are also other values in these rows such as: '5335154', test4559#me.com', '555-555-5555'. Filtering those out will need to be taken into account.
...where stringcolumn like '4[0-4][0-9]' OR stringcolumn = '450'
You don't need the wildcard if you want to restrict to 3 digits.
Use regex to accomplish this.
...where stringcolumn like '4[0-4][0-9]' OR stringcolumn like '450'
one way
WHERE Column like '%4[0-4][09]%'
OR Column LIKE '%500%'
keep in mind that this will pick anything with the number in it, so 5000 will be returned as well
I would do the following:
select t.*
from (select t.*,
(case when charindex('4', col) > 0
then substrint(col, charindex('4', col), charindex('4', col) + 2)
end) as col4xx
from t
) t
where (case when isnumeric(col4xx) = 1
then (case when cast(col4xx as int) between 400 and 450 then 'true'
end)
end) = 'true'
I'm not a fan of having case statements in WHERE clauses. However, to ensure conversion to a number, this is needed (or the conversion could become a column in another subquery). Note that the following is not equivalent:
where col4xx between '400' and '450'
Since the string '44A' would match.

How can I ORDER anything that looks like a number, as a number in T-SQL?

I have a column named Code that is varchar(3).
It contains numbers and strings as well. For example: ' 1', '234', 'Xxx', '9 ','Aa ' etc.
Is there way -just like in MS EXCEL- ORDER anything that looks like a number, as a number?
So that output for the given example above will be:
1. 1
2. 234
3. 9
4. Aa
5. Xxx
ORDER BY CASE WHEN ISNUMERIC(YourField) = 1 THEN CONVERT(INT, YourField) - 500 ELSE ASCII(LOWER(YourField)) END
If the field can be converted to a number it is sorted by number otherwise it uses ASCII coding to sort. I have used "- 500" just so there is no cross over in the sort, and to ensure numbers are sorted ahead of text.
ADDENDUM:
Brian Arsuaga has posted a more robust solution to this which I actually prefer, but since this has already been marked as the answer I am adding his solution to this for the benefit of anyone reading this in the future.
ORDER BY
ISNUMERIC(YourField) DESC,
CASE WHEN ISNUMERIC(YourField) = 1 THEN CONVERT(INT, YourField) ELSE 0 END,
YourField
If you don't like using an arbitrary sentinel (500), which might cause sorting issues depending on the range of numbers you expect, you can use multiple expressions for the ordering.
-- put the numbers at the top
ORDER BY ISNUMERIC(YourField) DESC,
-- sort the numbers as numbers, sort the strings as nothing
CONVERT(INT, CASE WHEN ISNUMERIC(YourField) = 1 THEN YourField ELSE '0' END),
-- sort the strings
YourField
The last term is only a tiebreaker when either two terms are both numbers with the same value ('01', '1') or two terms are both non-numbers. For non-numbers, their first and second terms will always be 0.
More complicated, but maybe a little more safe.
Edited to add a nice comparison with the help of the guy below
create table #t
(
YourField varchar(4)
)
insert into #t(YourField) Values('1'), ('3'), ('234'), ('0'), ('00'),
('09'), ('9'), ('1a'), ('aaa'), ('aba'), ('-500')
Select YourField from #t
ORDER BY ISNUMERIC(YourField) DESC,
CONVERT(INT, CASE WHEN ISNUMERIC(YourField) = 1 THEN YourField ELSE '0' END),
YourField
drop table #t