web-dev-qa-db-fra.com

MYSQL sum () pour des lignes distinctes

Je cherche de l'aide pour utiliser sum () dans ma requête SQL:

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;

J'utilise DISTINCT parce que je fais "group by" et cela garantit que la même ligne n'est pas comptée plus d'une fois.

Le problème est que SUM (conversions.value) compte la "valeur" pour chaque ligne plus d'une fois (en raison du regroupement par)

Je veux essentiellement faire SUM(conversions.value) pour chaque conversion DISTINCT.id.

Est-ce possible?

41
makeee

Je peux me tromper mais d'après ce que je comprends

  • conversions.id est le clé primaire de votre table conversions
  • stats.id est le clé primaire de votre table stats

Ainsi, pour chaque conversions.id, vous avez au plus un links.id impacté.

Votre demande, c'est un peu comme faire le produit cartésien de 2 sets:

[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 

et pour chaque lien, vous obtenez des lignes sizeof ([clics]) x sizeof ([conversions])

Comme vous l'avez noté, le nombre de conversions uniques dans votre demande peut être obtenu via un

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

ce distinct parvient à supprimer toutes les lignes [clics] dans le produit cartésien

mais clairement

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

Dans votre cas, depuis

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

vous avez

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

donc je testerais votre demande avec

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;

Tiens moi au courant ! Jérôme

73
Jerome WAGNER

La solution Jeromes est en fait fausse et peut produire des résultats incorrects !!

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

supposons le tableau suivant

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

la somme de valeur correcte pour des identifiants distincts serait de 8. La formule de Jérôme produit:

sum(conversions.value) = 18
count(distinct conversions.id) = 3
count(*) = 5
18*3/5 = 9.6 != 8
11
Clemens Valiente

Pour une explication de la raison pour laquelle vous voyez des chiffres incorrects, lire ceci.

Je pense que Jerome a une idée de ce qui cause votre erreur. La requête de Bryson fonctionnerait, bien que cette sous-requête dans SELECT puisse être inefficace.

7
TehShrike

Utilisez la requête suivante:

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
4
Bryson

J'utilise une sous-requête pour ce faire. Il élimine les problèmes de regroupement. La requête serait donc quelque chose comme:

SELECT COUNT(DISTINCT conversions.id)
...
     (SELECT SUM(conversions.value) FROM ....) AS Vals
3
Dave

Que diriez-vous quelque chose comme ça:

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  
2
Quesi

Cela fera l'affaire, divisez simplement la somme avec le nombre d'ID de conversation qui sont en double.

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
1
Dipu Raj