2012-03-18 18 views
14

Tengo siguiente consulta:Rails 3, ActiveRecord, PostgreSQL - ¿El comando ".uniq" no funciona?

Article.joins(:themes => [:users]).where(["articles.user_id != ?", current_user.id]).order("Random()").limit(15).uniq 

y me da el error

PG::Error: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list 
LINE 1: ...s"."user_id" WHERE (articles.user_id != 1) ORDER BY Random() L... 

Cuando actualizo la consulta original a

Article.joins(:themes => [:users]).where(["articles.user_id != ?", current_user.id]).order("Random()").limit(15)#.uniq 

por lo que el error se ha ido ... En MySQL .uniq funciona, en PostgreSQL no. Existe alguna alternativa?

+0

¿Estás seguro de que la consulta con 'uniq' arroja resultados diferentes? Por favor, muestre consultas SQL reales para cada variante (use el método 'sql'). – taro

+0

Estoy seguro. Cuando utilicé esta consulta con la base de datos MySQL, entonces sin '.uniq' me devolvió también la misma fila, pero con' .uniq' siempre una única fila. En PostgreSQL si uso '.uniq', obtengo el error especificado arriba, si no uso' .uniq', entonces el error se ha ido, pero también estoy obteniendo las mismas filas de DB. – user984621

Respuesta

30

Como el error indica for SELECT DISTINCT, ORDER BY expressions must appear in select list. Por lo tanto, debe seleccionar explícitamente para la cláusula que está ordenando.

Aquí hay un ejemplo, es similar a su caso pero se generaliza un poco.

Article.select('articles.*, RANDOM()') 
     .joins(:users) 
     .where(:column => 'whatever') 
     .order('Random()') 
     .uniq 
     .limit(15) 

Por lo tanto, incluyen de manera explícita su cláusula ORDER BY (en este caso RANDOM()) usando .select(). Como se muestra arriba, para que su consulta devuelva los atributos del Artículo, también debe seleccionarlos explícitamente.

Espero que esto ayude; buena suerte

+2

¿Por qué incluso debe agregar lo que está ordenando a la cláusula de selección en primer lugar en postgresql. Si está utilizando una unión, entonces la sql debe ser lo suficientemente inteligente como para saber qué ordenar sin declararlo explícitamente en la cláusula de selección (especialmente dado que la cláusula de selección está destinada a limitar las columnas devueltas). – JohnMerlino

+0

¿La inclusión de 'RANDOM()' no anula por completo 'DISTINCT' porque toma en cuenta un conjunto de valores completamente únicos? Y como tal, terminas con registros duplicados como si no hubieras usado el 'DISTINCT' en primer lugar? –

1

Supongo que el método .uniq se traduce en una cláusula DISTINCT en el SQL. PostgreSQL es quisquilloso (más selectivo que MySQL): todos los campos de la lista de selección al usar DISTINCT deben estar presentes en las cláusulas ORDER_BY (y GROUP_BY).

No está claro qué está intentando hacer (¿un pedido aleatorio?). Además de publicar el SQL completo enviado, si pudiera explicar su objetivo, podría ser útil para encontrar una alternativa.

+0

Probablemente tengas razón, pero ¿existe alguna forma elegante de integrar en la consulta anterior 'cláusula DISTINCT'? Mi consulta actual es "bastante corta", puedo usar 'find_by_sql' y estoy listo para configurar' DISTINCT' clausule, pero en este caso sería la consulta mucho más grande. – user984621

0

Acabo de actualizar mi aplicación 100% funcionando y probada de 3.1.1 a 3.2.7 y ahora tengo este mismo PG :: Error.

estoy usando Cancan ...

@users = User.accessible_by (current_ability) .order ('asc lname'). Uniq

Extracción de la .uniq resuelve el problema y que no era necesario de todos modos para esta simple consulta.

Todavía mirando a través de las notas de cambio entre 3.1.1 y 3.2.7 para ver qué causó esto para romper.

2

Solo para enriquecer el hilo con más ejemplos, en caso de que haya anidado las relaciones en la consulta, puede intentar con la siguiente declaración.

Person.find(params[:id]).cars.select('cars.*, lower(cars.name)').order("lower(cars.name) ASC") 

En el ejemplo dado, usted está pidiendo todos los coches para una persona determinada, ordenados por nombre de modelo (Audi, Ferrari, Porsche)

No creo que esto es una mejor manera, pero puede ayudar a abordar este tipo de situación pensando en objetos y colecciones, en lugar de hacerlo en una forma relacional (Base de datos).

Gracias!

Cuestiones relacionadas