2011-01-02 17 views
9

Tengo una tablaMySQL LEFT JOIN, GROUP BY y ORDER BY no funciona como se requiere

'products' => ('product_id', 'name', 'description') 

y una mesa

'product_price' => ('product_price_id', 'product_id', 'price', 'date_updated') 

Quiero realizar una consulta algo así como

SELECT `p`.*, `pp`.`price` 
FROM `products` `p` 
LEFT JOIN `product_price` `pp` ON `pp`.`product_id` = `p`.`product_id` 
GROUP BY `p`.`product_id` 
ORDER BY `pp`.`date_updated` DESC 

Como probablemente pueda adivinar, el precio cambia a menudo y necesito sacar el último. El problema es que no puedo resolver cómo ordenar la mesa LEFT JOINed. Intenté usar algunas de las funciones de GROUP BY como MAX() pero eso solo sacaría la columna, no la fila.

Gracias.

+0

Puede explicar lo que le gustaría a pasar? ¿Quieres ordenar por el máximo del grupo? ¿Quieres unirte solo a la última actualización? Quizás algunos datos de ejemplo y el resultado esperado de esos datos ayudarían a aclarar su pregunta. –

+0

¿Por qué no unirse internamente? –

+0

Tengo un producto con 5 precios diferentes con diferentes fechas de 'fecha_actualizadas'. Necesito unirme y sacar el último precio. – Simon

Respuesta

15

Parece que es imposible para usar un ORDER BY en un resumen GROUP BY. Mi lógica fundamental es defectuosa. Tendré que ejecutar la siguiente subconsulta.

SELECT `p`.*, `pp`.`price` FROM `products` `p` 
LEFT JOIN (
    SELECT `price` FROM `product_price` ORDER BY `date_updated` DESC 
) `pp` 
ON `p`.`product_id` = `pp`.`product_id` 
GROUP BY `p`.`product_id`; 

Esto tomará un impacto en el rendimiento, pero ya que es el mismo para cada fila subconsulta no debe ser demasiado malo.

+0

Hice una pregunta similar justo ahora y obtuve esta respuesta de @Gordon Linoff http://stackoverflow.com/a/18763815/570796 – superhero

1

Es necesario configurar los alias correctamente que pienso y también establece lo que se está uniendo en:

SELECT p.*, pp.price 
FROM products AS p 
LEFT JOIN product_price AS pp 
ON pp.product_id = p.product_id 
GROUP BY p.product_id 
ORDER BY pp.date_updated DESC 
+0

Gracias. Me perdí la parte ON. He editado mi consulta. Creo que la parte AS es opcional. – Simon

-1

Esto le dará el último precio de actualización:

select 
    p.*, pp.price 
from 
    products p, 
    -- left join this if products may not have an entry in prodcuts_price 
    -- and you would like to see a null price with the product 
    join 
    (
     select 
     product_price_id, 
     max(date_updated) 
     from products_price 
     group by product_price_id 
    ) as pp_max 
    on p.product_id = pp.product_id 
    join products_price pp on 
    pp_max.prodcuts_price_id = pp.products_price_id 
+0

Esto probablemente funcionaría sin embargo me gustaría evitar hacer una subconsulta ya que tengo un gran conjunto de datos. – Simon

+0

Esa es la forma en que da resultados correctos. Otras consultas darán ** todos ** precios. Pero bueno, si trabajan más rápido solo usa ese derecho ...? @! –

+0

Agradezco su ayuda, pero mi consulta no da todos los precios, solo me da un precio aleatorio que espero resolver ordenando correctamente. – Simon

-2

Mysqlism:

SELECT p.*, MAX(pp.date_updated), pp.price 
FROM products p 
LEFT JOIN product_price pp ON pp.product_id = p.product_id 
GROUP BY p.product_id 

trabajará en algunos RDBMS:

SELECT p.*, pp.date_updated, pp.price 
FROM products p 
LEFT JOIN product_price pp ON pp.product_id = p.product_id 
WHERE (p.product_id, pp.date_updated) 

    in (select product_id, max(date_updated) 
     from product_price 
     group by product_id) 

funcionará en la mayoría de los RDBMS:

SELECT p.*, pp.date_updated, pp.price 
FROM products p 
LEFT JOIN product_price pp ON pp.product_id = p.product_id 

WHERE EXISTS 
(
    select null -- inspired by Linq-to-SQL style :-) 
    from product_price 

    WHERE product_id = p.product_id 

    group by product_id 

    HAVING max(date_updated) = pp.date_updated 
) 

funcionará en todos los RDBMS:

SELECT p.*, pp.date_updated, pp.price 
FROM products p 
LEFT JOIN product_price pp ON pp.product_id = p.product_id 

LEFT JOIN 
(
    select product_id, max(date_updated) as recent 
    from product_price 
    group by product_id 
) AS latest 
ON latest.product_id = p.product_id AND latest.recent = pp.date_updated 

Y si nate c la intención del código es obtener solo una fila de product_price, no es necesario table-derive (es decir join (select product_price_id, max(date_updated) from products_price) as pp_max), que puede ser que también acaba de simplificar (es decir, sin necesidad de utilizar la clave primaria sustituta product_price_id) es similar a la siguiente:.

SELECT p.*, pp.date_updated, pp.price 
FROM products p 
LEFT JOIN product_price pp ON pp.product_id = p.product_id 
WHERE pp.date_updated = (select max(date_updated) from product_price) 
+0

Tu Mysqlism no funciona. Ese es todo el sentido de esta publicación. El precio que se selecciona no ** tiene que ** aunque puede elegir el precio que coincide con la fecha máxima. http://dev.mysql.com/doc/refman/5.5/en/group-by-hidden-columns.html –

+0

La última consulta no tiene nada que ver con mi intención. –

+0

Ese es el punto, falta la cláusula GROUP BY en su subconsulta; así que, naturalmente, recogerá solo una fila. A continuación, agregue un GROUP BY en su subconsulta, utilizando product_price_id; Puedo arriesgarme a suponer que product_price_id es una clave primaria sustituta, y lo que es más, es una identificación secuencial, whatdyathink? ¿Por qué utilizar GROUP BY en único en cada fila en una tabla? es absurdo En cuanto a Mysqlism, no estoy seguro de mi respuesta al respecto, no tengo MySQL en mi caja, pensé que MySQL GROUP BY tenía superpoderes, pensé que tenía la funcionalidad DISTINCT ON de Postgresql, su primera respuesta me llevó a pensar : -/ – Hao