0

Considering the following query:

SELECT 1 AS a, '100' AS b
UNION
SELECT 1 AS a, '50' AS b
ORDER BY a, b;

which results in:

a    b
1  '100'
1  '50'

What I really want is to sort column b by number and not text.

One possible solution could be:

SELECT 1 AS a, '100' AS b, '100'::int AS c
UNION
SELECT 1 AS a, '50' AS b, '50'::int AS c
ORDER BY a, c;

Which results in the ordering of:

a    b     c
1  '50'   50
1  '100'  100

as desired.

This is quite satisfying but if I have 1 mio. result rows then I would also have 1 mio. values transferred in the result response which I do not need.

Is there a neater way of converting column values when ordering?

I am looking for a way of letting the SQL server convert the column values "within" the ORDER BY clause but only returning the "original" result columns.

Community
  • 1
  • 1
m13r
  • 2,458
  • 2
  • 29
  • 39

4 Answers4

1

you can do this with a subquery (think the union is part of the problem).

select a, b
from (
      SELECT 1 AS a, '100' AS b
      UNION
      SELECT 1 AS a, '50' AS b)s
order by cast(b as int)-- or b::int

see SqlFiddle with difference

But if it's just a sample, and b is a varchar type in your table, you can do

select a, b
from YourTable
order by a, cast(b as int)

without any subquery.

Raphaël Althaus
  • 59,727
  • 6
  • 96
  • 122
1

Dealing with strings is best handled by strings, if any value in that column isnt convertible to integer it will fail.

SELECT
      a, b
FROM (
      SELECT 1 AS a, '100' AS b
      UNION ALL
      SELECT 1 AS a, '50' AS b
      UNION ALL
      SELECT 1 AS a, 'badvalue' AS b
     ) s
ORDER BY
      a, right(concat('000000000',b),8)
;

| A |        B |
|---|----------|
| 1 |       50 |
| 1 |      100 |
| 1 | badvalue |

BUT:

SELECT
      a, b
FROM (
      SELECT 1 AS a, '100' AS b
      UNION ALL
      SELECT 1 AS a, '50' AS b
      UNION ALL
      SELECT 1 AS a, 'badvalue' AS b
     ) s
ORDER BY
      a, b::int
;

ERROR: invalid input syntax for integer: "badvalue": SELECT

http://sqlfiddle.com/#!15/d41d8/3109


EDIT in response to leading +/- negative characters

SELECT
      a, b
FROM (
      SELECT 1 AS a, '-100' AS b
      UNION ALL
      SELECT 1 AS a, '-50' AS b
      UNION ALL
      SELECT 1 AS a, '100' AS b
      UNION ALL
      SELECT 1 AS a, '50' AS b
      UNION ALL
      SELECT 1 AS a, 'badvalue' AS b
     ) s
ORDER BY
      a
    , case when left(b,1) = '-' then right(concat('000000000',b),8)
           else right(concat('11111111',replace(b,'+','')),8)
      end
;

http://sqlfiddle.com/#!15/d41d8/3112

Paul Maxwell
  • 33,002
  • 3
  • 32
  • 51
0

Yes either just use numbers in the insert

SELECT 1 AS a, 100 AS b
UNION
SELECT 1 AS a, 50 AS b
ORDER BY a, b;

cast to a number before insert,

SELECT 1 AS a, cast('100' as integer) AS b
UNION
SELECT 1 AS a, cast('50' as integer) AS b
ORDER BY a, b;

or in Order By

SELECT 1 AS a, 100 AS b
UNION
SELECT 1 AS a, 50 AS b
ORDER BY a, cast(b as integer); 
Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
0

Cast the column b values.

Example:

order by a, cast(b as numeric)

Community
  • 1
  • 1
Adi
  • 232
  • 1
  • 9