Complex issue with the way Looker calculates totals

Looker offers to calculate the total in addition to the details in an Explore:
 

8236db4e-7716-4112-aca0-2036831bbbd1.png

This has always been a bit tricky, and in my opinion a suboptimal way to go.
Today, however, I encountered a problem that actually makes this path become ridiculous, and I don't know how to get around it either.
 

5f02f78d-dd13-4b2d-b313-ca7c11e3a6be.png

Here I now have the case where I only want to see the market value where the OP <> 0.
How does looker do that?

 

SELECT
SUM ( sum_op ) AS sum_op
, SUM ( marketvalue ) AS marketvalue
WHERE bla = bla
HAVING sum_op <> 0

Of course, this approach cannot work at all, because the sum over everything, i.e. without the elements (see screenshot 1) is not <> 0. Therefore, the total that looker calculates does not match the correct total.

The bad thing is: I don't see any model-technical way to get around this.
This is clearly a BUG for me as a customer, as the totals do not match the displayed values and my customer cannot trust the displayed totals.
With a dummy example like the one shown, the human being is still easily able to see the error.
But already with 10 lines, this is not noticeable and leads to wrong business decisions.

Hence my question:
Have you also noticed this problem and have you found solutions for it?

by the way:
this is the solution proposed by Looker!
However, it is not suitable for end users, but only for developers:
https://cloud.google.com/looker/docs/best-practices/how-to-troubleshoot-looker-totals

Thank you for your feedback and advice!
Ben

1 3 1,900
3 REPLIES 3

I thought about it again and found a - I think - simple solution.
We as users can't implement it, but it shouldn't be rocket science for Looker/Google.
 

To fix the problem with the wrong totals, Looker/Google would only have to rewrite the TOTAL statement minimally and enclose it with a CTE or a subquery / inner query.

/* Currently, Looker computes the detail values and the total using the following method: */
SELECT
attribute_1
, attribute_2 SUM ( sum_op ) AS sum_op
, SUM ( marketvalue ) AS marketvalue
WHERE
bla = bla
GROUP BY attribute_1
, attribute_2
HAVING
sum_op <> 0
;
-- sql for creating the total and/or determining pivot columns
SELECT
SUM ( sum_op ) AS sum_op
, SUM ( marketvalue ) AS marketvalue
WHERE
bla = bla
HAVING
sum_op <> 0
;
FETCH NEXT 1 rows only
/* Solution */
SELECT
attribute_1
, attribute_2 SUM ( sum_op ) AS sum_op
, SUM ( marketvalue ) AS marketvalue
WHERE
bla = bla
GROUP BY attribute_1
, attribute_2
HAVING
sum_op <> 0
;
-- sql for creating the total and/or determining pivot columns
SELECT
SUM ( sum_op ) AS sum_op
, SUM ( marketvalue ) AS marketavalue
FROM (
SELECT
attribute_1
, attribute_2 SUM ( sum_op ) AS sum_op
, SUM ( marketvalue ) AS marketvalue
WHERE
bla = bla
GROUP BY attribute_1
, attribute_2
HAVING
sum_op <> 0
)
;
FETCH NEXT 1 rows only

Hey @moebe 

I encountered the same issue and found that using table calculations suggested by Google isn't viable because it limits the result set to 5000 records.

Have you found an alternative solution? Your total statement seems like it would work well, considering it incorporates all row-level logic.

Best,

Christian

Hi @moebe,

Your problem is that you are filtering on the sum, which results in a HAVING argument instead of a WHERE. HAVING is computed after the sum, so the total is not correct.

I suggest that you create the sum of OP and Marketvalue in a PDT. You can then use them as dimensions and filter on OP > 0. A measure will be used to display the sum of OP and Marketvalue in the data table.

 

view: test {
derived_table: {
  sql: SELECT * FROM (
  VALUES 
    ('ID.1', 'FLOAT', 2.64, 137110), 
    ('ID.2', 'FIXED', 0.00, 228930), 
    ('ID.3', 'FIXED', 0.00, -228930), 
    ('ID.4', 'FLOAT', 0.00, -137110)
) AS t(id, price_status, op, marketvalue);;
}

  dimension: id {
    primary_key: yes
    label: "ID"
    type: string
    sql: ${TABLE}.id;;
  }

  dimension: price_status {
    type: string
    sql: ${TABLE}.price_status;;
  }

  dimension: op {
    label: "OP"
    type: number
    sql: ${TABLE}.OP;;
  }

  dimension: marketvalue {
    type: number
    sql: ${TABLE}.marketvalue ;;
  }

  measure: sum_op {
    label: "Sum OP"
    type: sum
    sql: ${op} ;;
  }
  
  measure: sum_marketvalue {
    type: sum
    sql: ${marketvalue} ;;
  }
  
}

 

Here is the table unfiltered:
Screenshot 2025-03-19 at 23.34.01.png
Here is the table filtered on OP > 0.
Screenshot 2025-03-19 at 23.34.32.png

Hope this helps!

Top Labels in this Space
Top Solution Authors