ORDENAR POR la ​​lista de valores IN

Resuelto nutcracker asked hace 15 años • 17 respuestas

Tengo una consulta SQL simple en PostgreSQL 8.3 que capta muchos comentarios. Proporciono una lista ordenada de valores a la INconstrucción en la WHEREcláusula:

SELECT * FROM comments WHERE (comments.id IN (1,3,2,4));

Esto devuelve comentarios en un orden arbitrario que en mi caso son identificadores como 1,2,3,4.

Quiero que las filas resultantes estén ordenadas como la lista en la INconstrucción: (1,3,2,4).
¿Cómo lograr eso?

nutcracker avatar May 15 '09 07:05 nutcracker
Aceptado

Puede hacerlo con bastante facilidad con (introducido en PostgreSQL 8.2) VALORES (), ().

La sintaxis será así:

select c.*
from comments c
join (
  values
    (1,1),
    (3,2),
    (2,3),
    (4,4)
) as x (id, ordering) on c.id = x.id
order by x.ordering
 avatar May 15 '2009 08:05

Úselo WITH ORDINALITYen Postgres 9.4 o posterior.

SELECT c.*
FROM   comments c
JOIN   unnest('{1,3,2,4}'::int[]) WITH ORDINALITY t(id, ord) USING (id)
ORDER  BY t.ord;
  • No es necesaria una subconsulta, podemos usar la función de retorno de conjuntos directamente como una tabla, también conocida como "función de tabla".

  • Un literal de cadena para pasar la matriz en lugar de un constructor ARRAY puede ser más fácil de implementar con algunos clientes.

  • Por conveniencia (opcionalmente), haga coincidir el nombre de la columna a la que nos estamos uniendo ("id" en el ejemplo), para que podamos unirnos con una USINGcláusula corta y solo obtener una única instancia de la columna de unión en el resultado.

  • Funciona con cualquier tipo de entrada. Si su columna clave es del tipo text, proporcione algo como '{foo,bar,baz}'::text[].

Explicación detallada:

  • PostgreSQL unnest() con número de elemento
Erwin Brandstetter avatar Feb 17 '2016 12:02 Erwin Brandstetter

Simplemente porque es muy difícil de encontrar y hay que difundirlo: en mySQL esto se puede hacer mucho más sencillo , pero no sé si funciona en otros SQL.

SELECT * FROM `comments`
WHERE `comments`.`id` IN ('12','5','3','17')
ORDER BY FIELD(`comments`.`id`,'12','5','3','17')
das oe avatar Jan 15 '2012 21:01 das oe

Con Postgres 9.4 esto se puede hacer un poco más corto:

select c.*
from comments c
join (
  select *
  from unnest(array[43,47,42]) with ordinality
) as x (id, ordering) on c.id = x.id
order by x.ordering;

O un poco más compacto sin una tabla derivada:

select c.*
from comments c
  join unnest(array[43,47,42]) with ordinality as x (id, ordering) 
    on c.id = x.id
order by x.ordering

Eliminando la necesidad de asignar/mantener manualmente una posición a cada valor.

Con Postgres 9.6 esto se puede hacer usando array_position():

with x (id_list) as (
  values (array[42,48,43])
)
select c.*
from comments c, x
where id = any (x.id_list)
order by array_position(x.id_list, c.id);

El CTE se utiliza para que la lista de valores solo sea necesario especificar una vez. Si eso no es importante esto también se puede escribir como:

select c.*
from comments c
where id in (42,48,43)
order by array_position(array[42,48,43], c.id);
 avatar Apr 13 '2015 06:04

Creo que así es mejor:

SELECT * FROM "comments" WHERE ("comments"."id" IN (1,3,2,4))
    ORDER BY  id=1 DESC, id=3 DESC, id=2 DESC, id=4 DESC
David Tran avatar Feb 28 '2012 02:02 David Tran