2010-03-12 12 views
39

estoy en busca de ayuda para utilizar suma() en mi consulta SQL:suma MYSQL() para las filas distintas

SELECT links.id, 
     count(DISTINCT stats.id) as clicks, 
     count(DISTINCT conversions.id) as conversions, 
     sum(conversions.value) as conversion_value 
FROM links 
LEFT OUTER JOIN stats ON links.id = stats.parent_id 
LEFT OUTER JOIN conversions ON links.id = conversions.link_id 
GROUP BY links.id 
ORDER BY links.created desc; 

utilizo DISTINCT porque estoy haciendo "grupo por" y esto asegura la misma fila no se cuenta más de una vez

El problema es que SUMA (conversions.value) cuenta el "valor" para cada fila más de una vez (debido al grupo por)

básicamente lo que quiero hacer SUM(conversions.value) para cada conversions.id distintas.

¿Es esto posible?

+1

Publicar la consulta completa sería útil. ¿Cómo se duplican los valores con un 'GROUP BY'? – Matthew

+0

¿Estás haciendo un join? Deberías publicar tu consulta. Hay algunas opciones que puede usar dependiendo de la consulta. –

+0

He actualizado mi pregunta con la consulta completa – makeee

Respuesta

58

puedo estar equivocado, pero por lo que entiendo

  • conversions.id es las primarias clave de su tabla de conversiones
  • stats.id es la clave principal de su tabla estadísticas

Así, para cada conversions.id que tienen a lo sumo un links.id afectada.

pedido es un poco como hacer el producto cartesiano de 2 juegos:

[clicks] 
SELECT * 
FROM links 
LEFT OUTER JOIN stats ON links.id = stats.parent_id 

[conversions] 
SELECT * 
FROM links 
LEFT OUTER JOIN conversions ON links.id = conversions.link_id 

y para cada enlace, se obtiene sizeof ([clics]) x sizeof ([conversiones]) líneas

Como se anotó el número de conversiones únicas en su solicitud se puede obtener a través de un

count(distinct conversions.id) = sizeof([conversions]) 

este distintivo se las arregla para eliminar todos los clics [] líneas en el producto cartesiano

pero claramente

sum(conversions.value) = sum([conversions].value) * sizeof([clicks]) 

En su caso, ya que

count(*) = sizeof([clicks]) x sizeof([conversions]) 
count(*) = sizeof([clicks]) x count(distinct conversions.id) 

tiene

sizeof([clicks]) = count(*)/count(distinct conversions.id) 

por lo que pondría a prueba su solicitud con

SELECT links.id, 
    count(DISTINCT stats.id) as clicks, 
    count(DISTINCT conversions.id) as conversions, 
    sum(conversions.value)*count(DISTINCT conversions.id)/count(*) as conversion_value 
FROM links 
LEFT OUTER JOIN stats ON links.id = stats.parent_id 
LEFT OUTER JOIN conversions ON links.id = conversions.link_id 
GROUP BY links.id 
ORDER BY links.created desc; 

¡Mantenme informado! Jerome

+5

¡Eres un genio! Casi pensé que no había una solución para esto hasta que encontré tu respuesta. –

+1

Excelente, esta solución es perfecta y bastante universal cuando no desea tratar con la solución de subconsultas dependientes que no es aceptable para grandes conjuntos de datos. –

+0

¡La solución Jeromes está realmente mal y puede producir resultados incorrectos! Ver mi respuesta a continuación. –

3

Utilizo una subconsulta para hacer esto. Elimina los problemas con la agrupación. lo que la consulta sería algo así como:

SELECT COUNT(DISTINCT conversions.id) 
... 
    (SELECT SUM(conversions.value) FROM ....) AS Vals 
+0

Pregunta actualizada con mi consulta completa. No estoy seguro de cómo integraría una subconsulta en lo que tengo y cómo afectaría el rendimiento. – makeee

+0

Las subconsultas normalmente tienen un impacto negativo en el rendimiento. Para minimizar el impacto, asegúrese de que cualquier subconsulta esté actuando en un índice. – Dave

4

utilizar la siguiente consulta:

SELECT links.id 
    , (
    SELECT COUNT(*) 
    FROM stats 
    WHERE links.id = stats.parent_id 
) AS clicks 
    , conversions.conversions 
    , conversions.conversion_value 
FROM links 
LEFT JOIN (
    SELECT link_id 
    , COUNT(id) AS conversions 
    , SUM(conversions.value) AS conversion_value 
    FROM conversions 
    GROUP BY link_id 
) AS conversions ON links.id = conversions.link_id 
ORDER BY links.created DESC 
2

¿Qué tal algo como esto:

select l.id, count(s.id) clicks, count(c.id) clicks, sum(c.value) conversion_value 
from (SELECT l.id id, l.created created, 
       s.id clicks, 
       c.id conversions, 
       max(c.value) conversion_value      
     FROM links l LEFT 
     JOIN stats s ON l.id = s.parent_id LEFT 
     JOIN conversions c ON l.id = c.link_id 
     GROUP BY l.id, l.created, s.id, c.id) t 
order by t.created 
6

Para una explicación de por qué estaban viendo números incorrectos, read this.

Creo que Jerome tiene una idea de lo que está causando el error. La consulta de Bryson funcionaría, aunque tener esa subconsulta en SELECT podría ser ineficiente.

+0

+1 para proporcionar una buena referencia sobre el uso de subconsultas. – kta

5

¡La solución Jeromes está realmente mal y puede producir resultados incorrectos!

sum(conversions.value)*count(DISTINCT conversions.id)/count(*) as conversion_value 

asumamos la siguiente tabla

conversions 
id value 
1 5 
1 5 
1 5 
2 2 
3 1 

la suma correcta de valor para los identificadores distintos sería 8. fórmula de Jerome produce:

sum(conversions.value) = 18 
count(distinct conversions.id) = 3 
count(*) = 5 
18*3/5 = 9.6 != 8 
+0

y la respuesta correcta es ..? – kleopatra

+1

Suponiendo que las conversiones.id es un campo único, no hay forma de que JOIN pueda producir 3 filas con converssions.id = 1 y solo 1 fila donde converssions.id = 2. La suposición de que converssions.id es única está implícita y probablemente deba hacerse explícito, pero aparte de eso, la fórmula es sólida. – Jonathan

1

Esto va a hacer el truco, simplemente divide la suma con el recuento de id de conversación que están duplicados.

SELECT a.id, 
     a.clicks, 
     SUM(a.conversion_value/a.conversions) AS conversion_value, 
     a.conversions 
FROM (SELECT links.id, 
     COUNT(DISTINCT stats.id) AS clicks, 
     COUNT(conversions.id) AS conversions, 
     SUM(conversions.value) AS conversion_value 
     FROM links 
     LEFT OUTER JOIN stats ON links.id = stats.parent_id 
     LEFT OUTER JOIN conversions ON links.id = conversions.link_id 
     GROUP BY conversions.id,links.id 
     ORDER BY links.created DESC) AS a 
GROUP BY a.id 
Cuestiones relacionadas