2010-02-12 20 views
5

Esta pregunta tiene un poco de historia — Is there a way to make a query respect the order of the inputted parameters?Hacer que PostgreSQL respete el orden de los parámetros ingresados?

Soy nuevo en la construcción de consultas "especializados", por lo que supone que si yo proporciono una cláusula IN como parte de una consulta SELECT, que va a volver resultados de la misma orden. Desafortunadamente ese no es el caso.

SELECT * FROM artists WHERE id IN (8, 1, 2, 15, 14, 3, 13, 31, 16, 5, 4, 7, 32, 9, 37) 
>>> [7, 32, 3, 8, 4, 2, 31, 9, 37, 13, 16, 1, 5, 15, 14] 

(No incluir la etapa donde solía Python para recorrer el resultado y anexar los ID de una lista.)

Así que la pregunta es, ¿hay una manera de hacer respetar la Postgres orden de los parámetros dados en una cláusula IN al devolver los resultados mismo orden?

Respuesta

5

Los resultados de la consulta se devolverán en orden no determinista a menos que especifique una cláusula ORDER BY.

Si realmente desea hacer la consulta de la manera que está solicitando, puede construir dicha cláusula. Aquí hay un ejemplo que usa parte de sus datos.

create table artists (
id integer not null primary key, 
name char(1) not null); 

insert into artists 
values 
    (8, 'a'), 
    (1, 'b'), 
    (2, 'c'), 
    (15, 'd'), 
    (14, 'e'), 
    (3, 'f'), 
    (13, 'g'); 

select * 
from artists 
where id in (8, 1, 2, 15, 14, 3, 13) 
order by 
    id = 8 desc, 
    id = 1 desc, 
    id = 2 desc, 
    id = 15 desc, 
    id = 14 desc, 
    id = 3 desc, 
    id = 13 desc; 

Basado en esto y en su otra pregunta, creo que hay algo mal con su modelo o la forma en que está tratando de hacer esto. Tal vez debería publicar una pregunta más genérica sobre cómo hacer lo que está tratando de hacer.

Si tiene artistas y tablas de clasificación, debería poder hacer algo como esto (o el equivalente a través de su ORM).

select 
    a.* 
from 
    artists a, 
    rankings r 
where 
    a.id = r.artist_id 
order by 
    r.score desc; 
+0

Gracias por su respuesta. Dejé mucho sobre cómo funciona mi aplicación. Para resumir, una clasificación no solo corresponde a un artista, sino que puede corresponder a cualquier cantidad de tipos de objetos que le demos. Dicho esto, estoy usando los genéricos de Django para crear esas relaciones, lo que hace que sea un poco más difícil hacer lo que estoy tratando de hacer aquí. –

+0

Es muy triste que Postgres no pueda conservar el orden. ¡Esto también me salvaría de muchos problemas! Estoy en una situación similar y el orden de clasificación cambia varias veces por minuto, por lo que estoy haciendo el pedido en mi aplicación para evitar escrituras de bases de datos totalmente innecesarias. Entonces, ordenar por no es una opción, – Malte

2

le sugiero que deje PostGreSQL devolver el conjunto en cualquier orden arbitrario (en especial, ya que es difícil de hacer control a nivel de SQL de grano fino a partir de una interfaz de Django), a continuación, ordenar de la manera que desee en Python - theresultset.sort(key=yourlistofids.index) debería funcionar bien (cuando theresultset es la lista de orden arbitraria que resulta de la base de datos y yourlistofids es la lista cuyo orden desea conservar).

+0

Otra situación en la que desearía poder aceptar ambas respuestas. :) Muchas gracias, personalmente voy a tomar esta ruta, pero para el interés de las personas que encuentran esta pregunta fuera de Google, voy a aceptar la respuesta de Cope. –

+0

FWIW, recomiendo en contra de esta solución. La base de datos está diseñada para ordenar, mientras que el idioma de la aplicación no. Será mucho más lento que dejar que la base de datos clasifique. – theory

+0

@Theory, Python es ** excelente ** en la clasificación (datos que se ajustan en la memoria) - su algoritmo 'timsort' es tan espléndido que también atrajo mucha atención, p. en el mundo de Java Es absurdo de su parte afirmar que (Python) "no está" "diseñado para ordenar" cuando es tan * grandioso * en eso. –

0

Otra forma:

SELECT * 
FROM artists 
WHERE id IN (8, 1, 2, 15, 14, 3, 13, 31, 16, 5, 4, 7, 32, 9, 37) 
ORDER BY POSITION(id::text in '(8, 1, 2, 15, 14, 3, 13, 31, 16, 5, 4, 7, 32, 9, 37)'); 
+0

La función de posición determina la posición de una cuerda en otra cuerda. Esto no funcionará correctamente porque no todos los identificadores tienen el mismo número de dígitos. Supongamos que quiere que id 14 sea el primero. Es posible que termine con id 1 como el primero. O id 4. –

Cuestiones relacionadas