4

I have this table with a character varying column in Postgres 9.6:

id | column 
------------
1  |IR ABC-1
2  |IR ABC-2
3  |IR ABC-10

I see some solutions typecasting the column as bytea.

select * from table order by column::bytea.

But it always results to:

id | column 
------------
1  |IR ABC-1
2  |IR ABC-10
3  |IR ABC-2

I don't know why '10' always comes before '2'. How do I sort this table, assuming the basis for ordering is the last whole number of the string, regardless of what the character before that number is.

8
  • 3
    10 comes before 2 because 1 comes before 2 Commented Apr 3, 2017 at 2:44
  • 1
    Have a look at the existing [postgresql] [natural-sort] questions. Commented Apr 3, 2017 at 3:09
  • 1
    If you want to sort by the name, and then subsort by the number, you'll have to separate the two entities into two columns, and then order by the two columns. Commented Apr 3, 2017 at 3:16
  • @evert, i think i can get somewhere with your idea.. but how do i split the column string? Commented Apr 3, 2017 at 3:34
  • 2
    If column is always in that format you have given in example, you can simply do split_part(column, '-', 2)::integer to get integer out of it. Otherwise regexp might be better. Commented Apr 3, 2017 at 7:06

2 Answers 2

3

When sorting character data types, collation rules apply - unless you work with locale "C" which sorts characters by there byte values. Applying collation rules may or may not be desirable. It makes sorting more expensive in any case. If you want to sort without collation rules, don't cast to bytea, use COLLATE "C" instead:

SELECT * FROM table ORDER BY column COLLATE "C";

However, this does not yet solve the problem with numbers in the string you mention. Split the string and sort the numeric part as number.

SELECT *
FROM   table
ORDER  BY split_part(column, '-', 2)::numeric;

Or, if all your numbers fit into bigint or even integer, use that instead (cheaper).

I ignored the leading part because you write:

... the basis for ordering is the last whole number of the string, regardless of what the character before that number is.

Related:

Typically, it's best to save distinct parts of a string in separate columns as proper respective data types to avoid any such confusion.

And if the leading string is identical for all columns, consider just dropping the redundant noise. You can always use a VIEW to prepend a string for display, or do it on-the-fly, cheaply.

Sign up to request clarification or add additional context in comments.

Comments

1

As in the comments split and cast the integer part

select *
from
    table
    cross join lateral
    regexp_split_to_array(column, '-') r (a)
order by a[1], a[2]::integer

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.