PostgreSQL: IN A SINGLE SQL SYNTAX order by numeric value computed from a text column

浪子不回头ぞ 提交于 2019-12-02 01:12:29

Seeing your name I cannot but post a simplification of your answer:

SELECT id, number_value_in_string FROM table
 ORDER BY CASE WHEN substr(number_value_in_string,1,2) = '1/'
        THEN 1/substr(number_value_in_string,3)::numeric 
        ELSE number_value_in_string::numeric END, id;

Ignoring possible divide by zero.

I would define a stored function to convert the string to a numeric value, more or less like this:

CREATE OR REPLACE FUNCTION fraction_to_number(s CHARACTER VARYING)
RETURN DOUBLE PRECISION AS
BEGIN
   RETURN
   CASE WHEN s LIKE '%/%' THEN
       CAST(split_part(s, '/', 1) AS double_precision) 
       / CAST(split_part(s, '/', 2) AS double_precision)
   ELSE
       CAST(s AS DOUBLE PRECISION)
   END CASE
END

Then you can ORDER BY fraction_to_number(weird_column)

If possible, I would revisit the data design. Is it all this complexity really necessary?

This postgres SQL does the trick:

select (parts[1] :: decimal) / (parts[2] :: decimal) as quotient
FROM (select regexp_split_to_array(number_value_in_string, '/') as parts from table) x

Here's a test of this code:

select (parts[1] :: decimal) / (parts[2] :: decimal) as quotient
FROM (select regexp_split_to_array('1/200', '/') as parts) x

Output:

0.005

Note that you would need to wrap this in a case statement to protect against divide-by-zero errors and/or array out of bounds issues etc if the column did not contain a forward slash

Note also that you could do it without the inner select, but you would have to use regexp_split_to_array twice (once for each part) and you would probably incur a performance hit. Nevertheless, it may be easier to code in-line and just accept the small performance loss.

I managed to solve my problem. Thanks all. It goes something like this, in a single SQL. (I'm using POSTGRESQL)

It will sort a string coming in as either "#", "#.#" or "1/#"

SELECT id, number_value_in_string FROM table ORDER BY CASE WHEN position('1/' in number_value_in_string) = 1 
    THEN 1/substring(number_value_in_string from (position('1/' in number_value_in_string) + 2) )::numeric 
    ELSE number_value_in_string::numeric 
END ASC, id

Hope this will help someone outhere in the future.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!