Lors du développement dans un projet, une erreur semblable à la suivante peut s'afficher dans une exploration ou dans l'outil de validation LookML:
Measures with Looker aggregations (sum, average, min, max, list types) may not reference other measures.
Cette erreur est causée par une mesure agrégée qui fait référence à une autre agrégation ou une autre mesure de n'importe quel type dans sa définition LookML, par exemple:
SELECT AVG((COUNT(*)) ) AS users.average_count FROM demo_db.users AS users
Les instructions SQL de ce type génèrent une agrégation double ou imbriquée en SQL. La plupart des dialectes SQL ne sont pas en mesure de double agréger ou d'imbriquer des agrégations, donc une telle tentative déclenche l'erreur.
Solutions
Il existe deux solutions :
- Utilisez des mesures non agrégées pour effectuer des instructions SQL non agrégées entre les mesures.
- Utilisez une table dérivée pour imbriquer des agrégations ou effectuer une double agrégation.
Utiliser des mesures non agrégées
Les mesures non agrégées (comme type: yesno
et type: number
) sont les seules mesures pouvant faire référence à d'autres mesures ou agrégations. Les mesures non agrégées n'effectuent aucune agrégation et ne peuvent donc pas effectuer d'agrégation double ou imbriquée. Les mesures de type: number
ou type: yesno
servent de repères afin que d'autres mesures ou combinaisons de mesures puissent y être référencées.
Par exemple, les mesures de type: number
permettent d'effectuer des calculs entre les mesures et de prendre n'importe quelle expression SQL valide qui donne un nombre ou un entier.
L'exemple suivant utilise un type: number
pour calculer le pourcentage de toutes les commandes annulées :
measure: order_count { # Base measure #1 type: count sql: ${order_id} ;; } measure: cancelled_orders { # Base measure #2 type: count filters: [status: "Cancelled"] } measure: percent_cancelled_orders { # New measure type: number sql: (1.0*${cancelled_orders})/ISNULL(${order_count},0) ;; }
Utiliser une table dérivée pour les agrégations doubles ou imbriquées
Mais que se passe-t-il si une agrégation imbriquée est nécessaire pour effectuer une analyse ? Par exemple, que se passe-t-il si vous avez besoin de connaître le montant moyen dépensé par les clients au cours de leur durée de vie (valeur vie client moyenne) ? Pour ce faire, vous devez utiliser deux niveaux d'agrégation (doublement ou imbrication), y compris :
-
Somme des ventes, regroupées par client
-
La moyenne de cette somme
Pour y parvenir avec LookML, vous pouvez essayer:
measure: total_revenue { type: sum sql: ${sale_price} ;; } measure: avg_customer_lifetime_value { type: average sql: ${total_revenue} ;; }
Toutefois, cela déclenche l'erreur, car la mesure avg_customer_lifetime_value
effectue une agrégation sur la mesure total_revenue
, qui est déjà une agrégation. Comme mentionné précédemment, la plupart des dialectes SQL déclenchent une erreur lorsque des agrégations doubles ou imbriquées sont utilisées dans une requête.
Pour obtenir une moyenne de la somme total_revenue
en SQL, une sous-requête comme celle-ci est nécessaire:
SELECT AVG(s.sum) FROM (SELECT SUM(x) as sum FROM ...) AS s
La solution équivalente dans Looker consiste à créer une table dérivée pour "aplatir" la mesure total_lifetime_value
dans un champ pouvant être agrégé. Dans Looker, on parle de dimensionnalisation d'une mesure. Avec une table dérivée, la mesure total_lifetime_value
devient une dimension. Vous pouvez ensuite créer une mesure de type: average
qui fait référence à la dimension customer_lifetime_value
:
view: customer_facts { derived_table: { sql: SELECT user_id, COALESCE(SUM(sale_price), 0) AS customer_lifetime_value FROM orders GROUP BY user_id;; } dimension: customer_lifetime_value { type: number sql: ${TABLE}."customer_lifetime_value" ;; } measure: average_customer_lifetime_value { type: average sql: ${customer_lifetime_value} ;; } }
Une fois la table dérivée customer_facts
jointe à une exploration, la mesure average_customer_lifetime_value
peut être utilisée pour effectuer l'analyse souhaitée dans une exploration sans déclencher d'erreur.