2009-06-30 8 views
14

Tengo esta consulta que funciona correctamente en MySQL. Más antecedentes en él here.Convertir la selección de MySQL a PostgreSQL

SELECT c.*, SUM(ABS(v.vote)) AS score 
FROM categories c,items i, votes v 
    WHERE c.id = i.category_id 
    AND i.id = v.voteable_id 
    AND v.created_at > '#{1.week.ago}' 
GROUP BY c.id 
ORDER BY score DESC LIMIT 8; 

He intentado ejecutarlo en PostgreSQL, y ha fallado con este mensaje de error.

PGError: ERROR: column "c.name" must appear in the GROUP BY clause or be used in an aggregate function

no estaba seguro de lo que esto significaba, así que traté de cambiar "c.id" a "c.name" en el grupo por la cláusula (ambos trabajan en MySQL la misma, asumiendo el nombre de un elemento es único).

Sin embargo esto sólo produce otro error similar

PGError: ERROR: column "c.id" must appear in the GROUP BY clause or be used in an aggregate function

¿Cómo se puede resolver este problema?

+1

Curiosamente, parece que esto ahora está permitido en Postgre 9.1 – you786

+0

¿Se eliminó en Postgre 9.2? Recibo este error por las mismas razones. – Aaron

+1

@ Aaron: no se eliminó, pero funciona solo cuando (se cita la [documentación] (http://www.postgresql.org/docs/current/static/sql-select).html)): _la columna desagrupada depende funcionalmente de las columnas agrupadas, ya que de lo contrario habría más de un valor posible para devolver para una columna desagrupada. Existe una dependencia funcional si las columnas agrupadas (o un subconjunto de las mismas) son la clave principal de la tabla que contiene la columna desagrupada_ –

Respuesta

11

Usted tiene que escribir el nombre de columna en la que SELECT está agrupando en:

SELECT c.id, c.name, SUM(ABS(v.vote)) AS score 
FROM categories c,items i, votes v 
    WHERE c.id = i.category_id 
    AND i.id = v.voteable_id 
    AND v.created_at > '#{1.week.ago}' 
GROUP BY c.id, c.name 
ORDER BY score DESC LIMIT 8; 

"No está permitido incluir nombres de columna en una cláusula SELECT que no se hace referencia en la cláusula GROUP BY"

+9

Está permitido en MySQL y es por eso que está confundido. Característica horrible en mi opinión – colithium

+0

Esto funcionó, gracias! –

8

Acabo de tener ese problema, pero yendo de MySQL a SQL Server. ¡Pensé que el hecho de que estaba permitido era extraño!

Sí, en la mayoría de las bases de datos, cuando se tiene una cláusula GROUP BY, solo se pueden seleccionar agregados de columnas o columnas que aparecen en la cláusula GROUP BY. Esto se debe a que no tiene forma de saber si las otras columnas que está seleccionando son realmente únicas o no.

Simplemente ponga las columnas que desee en GROUP BY si son únicas. Esta era una "característica" de MySQL que era cuestionable.

Puede leer sobre el comportamiento de MySQL y cómo es diferente here.

Ejemplo:

SELECT c.*, SUM(ABS(v.vote)) AS score 
FROM categories c,items i, votes v 
    WHERE c.id = i.category_id 
    AND i.id = v.voteable_id 
    AND v.created_at > '#{1.week.ago}' 
GROUP BY c.id, c.name, c.whatever_else 
ORDER BY score DESC LIMIT 8; 
+0

Gracias por el enlace MySQL, ¡tiene más sentido ahora! En este caso mi c.id siempre es único, así que probablemente estuvo bien, pero al menos ahora sé por qué lo hicieron. ¡Gracias! –

2

Si cambia su estado de cuenta a este que debería funcionar:

SELECT c.id, SUM(ABS(v.vote)) AS score 
FROM categories c,items i, votes v 
    WHERE c.id = i.category_id 
    AND i.id = v.voteable_id 
    AND v.created_at > '#{1.week.ago}' 
GROUP BY c.id 
ORDER BY score DESC LIMIT 8; 

No estoy seguro de lo que MySQL da como resultado, pero para darle una muy pequeña ejemplo de por qué esto no funciona en PostgreSQL, echar un vistazo a la categories siguiente tabla:

id | name 
---|----- 
1 | ABC 
1 | DEF 

Agrupe por id, por lo que cada fila en el resultado debe contener solo un id. Si selecciona name también, sin agrupar, ¿qué se debe mostrar en el resultado para name?

Puede ser ABC o DEF pero el motor de la base de datos realmente no puede decidirlo por usted (aunque aparentemente MySQL lo hace).

+1

¡MySQL elige uno al azar! ¿No es extraño? Hice una pregunta sobre esto hace unos días. – colithium

+0

Ni siquiera sabía que este era el caso. Muy extraño ... –

+0

Interesante ... en este caso, al menos mi id es siempre única, así que fue una buena columna para agrupar. También necesitaba el nombre de la categoría, por lo que acabo de enumerar tanto en la selección como en el grupo. Parece funcionar. ¡Gracias! –

Cuestiones relacionadas