PostgreSQL ORDER BY values in IN() clause

↘锁芯ラ 提交于 2020-06-08 17:28:01

问题


Ok, there are some answers out there on how to do this. But all of the answers are assuming that the query is selecting all. If you have a distinct select, the methods no longer work.

See here for that method: Simulating MySQL's ORDER BY FIELD() in Postgresql

Basically I have

SELECT DISTINCT id 
FROM items 
WHERE id IN (5,2,9) 
ORDER BY
 CASE id
  WHEN 5 THEN 1 
  WHEN 2 THEN 2
  WHEN 9 THEN 3
 END

Of course, this breaks and says

"PGError: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list"

Is there any way to order your query results in PostgreSQL by the order of the values in the IN clause?


回答1:


You can wrap it into a derived table:

SELECT *
FROM (
  SELECT DISTINCT id 
  FROM items 
  WHERE id IN (5,2,9) 
) t
ORDER BY
 CASE id
  WHEN 5 THEN 1 
  WHEN 2 THEN 2
  WHEN 9 THEN 3
 END



回答2:


From documentation:

Tip: Grouping without aggregate expressions effectively calculates the set of distinct values in a column. This can also be achieved using the DISTINCT clause (see Section 7.3.3).

SQL query:

SELECT id 
FROM items 
WHERE id IN (5,2,9) 
GROUP BY id
ORDER BY
    CASE id
        WHEN 5 THEN 1 
        WHEN 2 THEN 2
        WHEN 9 THEN 3
    END;



回答3:


Looking around I couldn't find a complete solution to this question.

I think the better solution is to use this query

SELECT *
FROM items
WHERE id IN (5,2,9) 
ORDER BY idx(array[5,2,9]::integer[], items.id)

If you are using PostgreSQL >= 9.2 you can enable the idx function enabling the extension.

CREATE EXTENSION intarray;

Otherwise you can create it with the following:

CREATE OR REPLACE FUNCTION idx(anyarray, anyelement)
  RETURNS INT AS 
$$
  SELECT i FROM (
     SELECT generate_series(array_lower($1,1),array_upper($1,1))
  ) g(i)
  WHERE $1[i] = $2
  LIMIT 1;
$$ LANGUAGE SQL IMMUTABLE;

I really suggest to use ::integer[] in the query because if you are creating the array dynamically is possible that it has no elements resulting in ids(array[], items.id) which would raise an exception on PostgreSQL.




回答4:


I create this function in postgres PL/PGSQL and it is a lot easier to use.

-- Function: uniqueseperategeomarray(geometry[], double precision)

-- DROP FUNCTION uniqueseperategeomarray(geometry[], double precision);

CREATE OR REPLACE FUNCTION manualidsort(input_id int, sort_array int[])
  RETURNS int AS
$BODY$
DECLARE
input_index int;
each_item int;
index int;
BEGIN
index := 1;
  FOREACH each_item IN ARRAY sort_array
  LOOP
    IF each_item = input_id THEN
      RETURN index;
    END IF;
    index := index+1;
  END LOOP;
END;
$BODY$
  LANGUAGE plpgsql;
ALTER FUNCTION manualidsort(int, int[])
  OWNER TO staff;

And when you run a query, go like this...

SELECT * FROM my_table ORDER BY manualidsort(my_table_id, ARRAY[25, 66, 54])


来源:https://stackoverflow.com/questions/6822651/postgresql-order-by-values-in-in-clause

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