2009-03-26 8 views
1

I ont cette structure de base de données:MySql aide de la requête: les joints avec des sommes et compte

TBL_A | TBL_B | TBL_C | TBL_D | TBL_E 
-------+---------+---------+---------+---------- 
id  | id_tbla | id_tbla | id_tbla | id 
name | id_user | id_user | id_user | name_tbla 
... | is_bool |   | weight | id_user 

Voici ce que je suis en train de réaliser:

SELECT 
    a.id, 
    a.name, 
    b.is_bool, 
    count(c.id_user) AS nb_views, 
    sum(d.weight) AS total_weight, 
    count(distinct e.id_user) AS distinct_users, 
FROM TBL_A AS a 
LEFT JOIN (TBL_B AS b) on (b.id_tbla = a.id) 
LEFT JOIN (TBL_C AS c) on (c.id_tbla = a.id) 
LEFT JOIN (TBL_D AS d) on (d.id_tbla = a.id) 
LEFT JOIN (TBL_E AS e) on (e.name_tbla = a.name) 
where a.id = 1 and e.id_user = 1 

La requête est effectuée, mais les résultats (nb_views, total_weight, distinct_users) sont erronés. Une idée pourquoi?

Répondre

1

Vous essayez de calculer trop d'agrégats dans une requête.

Enita non sunt multiplicanda praeter necessitatem

(latin, "les entités ne doivent pas être multipliées au-delà de la nécessité")

Vos tableaux B, C, D et E sont produits Cartesian Products l'un contre l'autre. Supposons que la rangée donnée en A correspond:

  • 3 rangs dans B
  • 6 rangs en C
  • 4 rangs dans D
  • une rangée E

Le nombre total de les lignes du résultat sont 3 * 6 * 4 * 1 = 72 lignes. Ainsi, votre count(c.id_user) est 12 fois ce qu'il devrait être, votre sum(d.weight) est 18 fois ce qu'elle devrait être, etc.

Le plus simple remède consiste à calculer chacun de ces agrégats dans une requête distincte:

SELECT a.id, a.name, COALESCE(b.is_bool, FALSE) AS is_bool 
FROM TBL_A AS a LEFT JOIN TBL_B AS b ON (b.id_tbla = a.id) 
WHERE a.id = 1; 

SELECT a.id, COUNT(c.id_user) AS nb_views 
FROM TBL_A AS a LEFT JOIN TBL_C AS c ON (c.id_tbla = a.id) 
WHERE a.id = 1; 

SELECT a.id, SUM(d.weight) AS total_weight, 
FROM TBL_A AS a LEFT JOIN TBL_D AS d ON (d.id_tbla = a.id) 
WHERE a.id = 1; 

SELECT a.id, COUNT(DISTINCT e.id_user) AS distinct_users, 
FROM TBL_A AS a LEFT JOIN TBL_E AS e 
    ON (e.name_tbla = a.name AND e.id_user = 1) 
WHERE a.id = 1; 
+0

Parfait! Vous m'avez même aidé à comprendre les chiffres que j'ai obtenus grâce à la demande. Je vais faire 4 demandes alors! Voilà pour essayer de tout faire en même temps pendant quelques heures ... :) – karlipoppins