2011-07-25 11 views
5

Ok, hay algunas respuestas sobre cómo hacer esto. Pero todas las respuestas presuponen que la consulta está seleccionando todas. Si tiene una selección distinta, los métodos ya no funcionan.PostgreSQL ORDER BY valores en la cláusula IN()

Vea aquí para ese método: Simulating MySQL's ORDER BY FIELD() in Postgresql

Básicamente tengo

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 

Por supuesto, esto rompe y dice

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

¿Hay alguna manera de ordenar los resultados de la consulta en PostgreSQL por el orden de los valores en la cláusula IN?

+0

"las expresiones _ORDER BY deben aparecer en la lista de selección_" - así que mueva la expresión a la lista SELECCIONAR :) – Karolis

Respuesta

7

se puede envolver en una tabla derivada:

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 
1

De 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).

consulta SQL:

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; 
0

puedo crear esta función en postgres PL/pgSQL y es mucho más fácil de usar.

-- 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; 

Y cuando se ejecuta una consulta, vaya como esto ...

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

Mirando a su alrededor no pude encontrar una solución completa a esta pregunta.

creo que la mejor solución es utilizar esta consulta

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

Si está utilizando PostgreSQL> = 9.2 se puede activar la función idx que permite la extensión.

CREATE EXTENSION intarray; 

De lo contrario se puede crear con lo siguiente:

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; 

Realmente recomiendo usar ::integer[] en la consulta, porque si va a crear la matriz dinámica es posible que no dispone de componentes que resultan en ids(array[], items.id) lo que generaría una excepción en PostgreSQL.

Cuestiones relacionadas