I am sorting songs in SQLite (on Android). I want to order them:
The first solution (when DB and application can be modified):
Add to your table single column e.g. solumntForSorting. Then on your application before inserting, concatenate your second condition ("With leading-digits at the end, by integer value.") as 0 or 1 to song name which first 'was cleaned' from undesired symbols. So on solumntForSorting you will get something like this: 0Im a Rainbow Too and 1911 is a Joke.
The second solution (when only application can be modified):
If you have to sort data excluding some symbols and you are not allowed to change your DB, you will get a slower selection because of filtering undesired values. Most of the overhead will be at CPU time and memory.
Using replace function is tedious from my point of view, that is why I suggest using CTE with list of values you want to drop, like this ('.', '.', ';', '(', ')', '''', '-'). CTE will be bulky like multiple replace but it is easier to modify and maintain.
Try this solution:
WITH RECURSIVE
ordering_name_substr(len, name, subsstr, hex_subsstr, number)
AS (SELECT length(name), name, substr(name, 1, 1), hex(substr(name, 1, 1)), 1
FROM songs
UNION ALL
SELECT len, name, substr(name, number + 1, 1),
hex(substr(name, number + 1, 1)), number + 1
FROM ordering_name_substr WHERE number < len),
last_order_cretaria(value, old_name)
AS (select GROUP_CONCAT(subsstr, ''), name
from ordering_name_substr
where hex_subsstr not in
('28', '29', '2C', '2E', '27') group by name )
SELECT S.n, S.name
FROM songs AS S LEFT JOIN last_order_cretaria AS OC
ON S.name = OC.old_name
ORDER BY
CASE WHEN name GLOB '[0-9]*' THEN 1
ELSE 0
END,
CASE WHEN name GLOB '[0-9]*' THEN CAST(name AS INT)
ELSE
OC.value
END
COLLATE NOCASE
I have tested on sqlfiddle.
In the list ('28', '29', '2C', '2E', '27')
you have values of ASCII codes (in hex) which you want to escape from be considered in ordering.
You also can try to use values itself like: ('.', '.', ';', '(', ')', '''', '-')
.
WITH RECURSIVE
ordering_name_substr(len, name, subsstr, number)
AS (SELECT length(name), name, substr(name, 1, 1), 1
FROM songs
UNION ALL
SELECT len, name, substr(name, number + 1, 1),
number + 1
FROM ordering_name_substr WHERE number < len),
last_order_cretaria(value, old_name)
AS (select GROUP_CONCAT(subsstr, ''), name
from ordering_name_substr
where subsstr not in
('.', '.', ';', '(', ')', '''', '-') group by name )
SELECT S.n, S.name
FROM songs AS S LEFT JOIN last_order_cretaria AS OC
ON S.name = OC.old_name
ORDER BY
CASE WHEN name GLOB '[0-9]*' THEN 1
ELSE 0
END,
CASE WHEN name GLOB '[0-9]*' THEN CAST(name AS INT)
ELSE
OC.value
END
COLLATE NOCASE
To make this sorting work fast and simple you have to be able to change your DB and application.