2010-01-11 8 views
7

Estoy ejecutando una consulta MySQL para clasificar a los usuarios de mi sitio de acuerdo con la cantidad de reseñas de libros y reseñas de recetas que han contribuido. Después de los problemas iniciales con una consulta JOIN múltiple, he cambiado a una serie de subconsultas, que es mucho, mucho más rápido. Sin embargo, aunque puedo extraer el número de revisiones de cada miembro, no puedo encontrar la manera de sumarlas para poder ordenar por el número total.¿Cómo agregar juntos los resultados de varias subconsultas?

Aquí está la consulta actual:

SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
FROM users 

necesito sumar bookreviews y recipereviews para conseguir '' reviewtotals. MySQL no le permitirá usar sintaxis simple para hacer cálculos en alias, pero supongo que hay otra manera de hacer esto.

+0

@mandel, tengo curiosidad acerca de sus problemas con 'JOIN' normalmente, yo a resolver este tipo de problema con un' JOIN' - ver mi respuesta para referencia. En mi experiencia, eso suele ser mucho más rápido para MySQL que múltiples subquerys correlacionadas como las que tiene. Me interesaría saber si en tu caso la solución de la subconsulta es más rápida que el JOIN. Te agradecería mucho si pudieras avisarme. –

+0

Mis problemas con JOIN provienen de la inexperiencia en lugar de la filosofía. Mi anterior JOIN resultó en una consulta terriblemente lenta - 9 segundos; Resultó que estaba creando un producto cartesiano. Pregunté sobre esto en SO aquí: http://stackoverflow.com/questions/2030032/is-performing-a-count-calculation-slowing-down-my-mysql-query. Cuando comencé a hacer subconsultas, la velocidad mejoró dramáticamente, ¡Y pude entender lo que estaba haciendo! – mandel

+0

Consulte mi respuesta a su publicación para una comparación de velocidad: su consulta JOIN es un poco más rápida, pero solo 4/100 de segundo con el tamaño de base de datos actual. – mandel

Respuesta

9

envolverlo en una subconsulta:

SELECT *, 
     bookreviews + recipereviews AS totalreviews 
FROM (
     SELECT users.*, 
       (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
       (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
       (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
     FROM users 
     ) q 
0

¿Ha intentado lo siguiente?

SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    ((SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) + 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID)) as reviewtotal 
FROM users 
+0

Gracias - esto es casi todo, pero aún necesito generar totales de bookreviews y recipereviews, así como la suma calculada. – mandel

1

Dos opciones:

Opción 1: feo es el infierno, y probablemente lenta (depende de la caché de consultas):

SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) + (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as reviewtotals 
FROM users 

Opción 2: guardar los resultados en una tabla temporal y a continuación, consulta esta tabla

Tal vez esto va a funcionar (no lo he probado)

SELECT *, bookreviews+recipereviews as reviewtotals FROM 
(SELECT users.*, 
    (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
    (SELECT count(*) FROM book_reviews WHERE book_reviews.user_id = users.ID) as bookreviews, 
    (SELECT count(*) FROM recipe_reviews WHERE recipe_reviews.user_id = users.ID) as recipereviews 
FROM users) u 
+0

El número dos casi funciona, pero debe agregar un alias a la primera subconsulta; sin embargo, es idéntico a la solución de @ Quassnoi, que fue en un minuto antes. ¡Gracias! – mandel

+0

Vi que había otra respuesta mientras escribía ... –

1

Si usted quiere estar seguro y rápido, hacerlo de esta manera:

SELECT users.* 
,  titles.num       titles 
,  book_reviews.num      book_reviews 
,  recipe_reviews.num     recipe_reviews 
,  book_reviews.num + recipe_reviews.num total_reviews 
FROM  users 
LEFT JOIN (
      SELECT user_ID, count(*) AS num 
      FROM  bookshelf 
      GROUP BY user_ID 
     ) as titles 
ON  users.ID = titles.user_ID 
LEFT JOIN (
      SELECT user_ID, count(*) AS num 
      FROM  book_reviews 
      GROUP BY user_ID 
     ) as book_reviews 
ON  users.ID = reviews.user_ID 
LEFT JOIN (
      SELECT user_ID, count(*) AS num 
      FROM  recipe_reviews 
      GROUP BY user_ID 
     ) as recipe_reviews 
ON  users.ID = recipes.user_ID 

Si usted quiere meter a las subconsultas en la lista SELECT, y quiere que sea seguro, eche un vistazo a la solución de Quassnoi.

Si te gusta vivir un poco dangersouly y todavía quieren un resultado rápido, puede utilizar las variables definidas por el usuario. Mi predicción es que estará seguro en este caso muy particular:

SELECT users.*, 
     (SELECT count(*) FROM bookshelf WHERE bookshelf.user_id = users.ID) as titles, 
     @bookreviews:=(
      SELECT count(*) 
      FROM book_reviews 
      WHERE book_reviews.user_id = users.ID 
     ) as bookreviews, 
     @recipereviews:=(
      SELECT count(*) 
      FROM recipe_reviews 
      WHERE recipe_reviews.user_id = users.ID 
     ) as recipereviews, 
     @bookreviews + @recipereviews as total_reviews 
FROM users 
+0

Interesante: la opción 1 es un poco más rápida que la solución de Quassnoi (0.02 segundos frente a 0.024 segundos), mientras que la Opción 2 es de 0.88 segundos, por lo que comparativamente es bastante más lenta. Encuentro que Quassnoi es mucho más simple en términos de legibilidad (y mi comprensión de lo que está sucediendo). ¿Hay ventajas en utilizar el método JOIN en su primer ejemplo? – mandel

+0

mandel: sí, las ventajas se vuelven rápidamente aparentes cuando los juegos con los que trabajas crecen de tamaño. el JOIN es mucho mejor escalable. Sin embargo, en estos tiempos de reloj, no creo que podamos decir nada concluyente. Despreciaría una diferencia tan pequeña. Pero aún debería ver diferencias considerables cuando obtiene más datos para tratar. La solución de subconsulta ejecuta cada subconsulta para cada fila de la consulta externa. Una unión de bucle anidado suele ser mucho más eficiente. –

Cuestiones relacionadas