views:

234

answers:

4

Hi,

Just asked a question pretty similar to this one...

Currently I am doing a very basic OrderBy in my statement.

SELECT * FROM tablename WHERE visible=1 ORDER BY position ASC, id DESC

The problem with this is that empty string entries for 'position' are treated as 0. Therefore all entries with position as empty string appear before those with 1,2,3,4. eg:

'', '', '', 1, 2, 3, 4

or

0, 0, 0, 1, 2, 3, 4

Is there a way to achieve the following ordering:

1, 2, 3, 4, '', '', ''.

or

1, 2, 3, 4, 0, 0, 0.

I assume the solution may have some kind of replace function but I haven't been able to find a function which does what I am after, through google.

Many Thanks,

JonB

+4  A: 
SELECT * 
FROM tablename 
WHERE visible=1 
ORDER BY 
    case when position in('', '0') then 1 else 0 end,
    position ASC, 
    id DESC
RedFilter
I think this will work but it's not the best solution. I think `position` should be an integer column ,and if that is the case, the `CASE` expression should use integers too, not strings. If `position` is not an integer or at least numeric, sorting as numbers won't work anyway. Also, this solutions adds a new column to sort for, which will likely have a negative impact on performance. If my assumption that `position` is actually an integer is correct, then the OP probably means `NULL` value where he wrote 'empty string', meaning you can simply write `ORDER BY COALESCE(position, ~0), id DESC`
Roland Bouman
@Roland: the OP implied pretty clearly that position is a string: *"The problem with this is that empty string entries for 'position' are treated as 0."*
RedFilter
OrbMan yes, he did. And I am saying that that is probably part of the problem. My suggestion was to give it a proper data type up front instead of trying to mop up afterwards.
Roland Bouman
@Roland: Oh, misunderstood you. I definitely agree with that! My assumption was that this was not an option, but definitely good to call it out.
RedFilter
A: 

you can trying joining two sub queries where one select id > 0 and not empty and the other select empty and 0 only

Funky Dude
A: 

You might try a CASE statement, like this:

SELECT *
FROM tablename
WHERE visible = 1
ORDER BY CASE position WHEN '' THEN '9999' ELSE position END CASE ASC,
    ID DESC
Scott Anderson
A: 

You say that position contains empty string entries...Do you really mean empty string, or do you mean NULL? If it actually contains NULL entries, you should use a slight modification of Orbman's statement:

SELECT * 
FROM tablename 
WHERE visible=1 
ORDER BY 
    COALESCE(position, ~0)
,   id DESC

COALESCE() returns the value of the first argument that is NOT NULL. The ~0 is a piece of black magic that will get you the maximum integer value supported by MySQL. (~ does a bitwise negation, turning all 0 bits to 1). So, in this case, if position IS NULL is true, it will return 18446744073709551615, else it will return the value of position.

I'd also like to point out that the data type of your position column should most likely be of some integer type (see http://dev.mysql.com/doc/refman/5.0/en/numeric-types.html). Because you mention empty strings, I think you should check your table definition by doing SHOW CREATE TABLE <tablename>. If position is not an integer type, I would advise you to change it. The main reason is that strings, even if they look like numbers, don't sort as numbers.

Roland Bouman