Skip to content

Greater than, less than, etc, not supported by measures #10148

@peterklingelhofer

Description

@peterklingelhofer

Describe the bug
There is an example online of using gte with dimensions, but not measures (https://cube.dev/blog/graphql-federation-example-with-apollo-federation-and-apollo-graphos). However, the Playground lets you attempt to filter by measures, but it errors. It creates a misconstructed SQL which results in a bad HAVING clause:

{
  "data": null,
  "errors": [
    {
      "message": "Error: unexpected token [HAVING]",
      "path": [
        "cube"
      ],
      "extensions": {
        "code": "DOWNSTREAM_SERVICE_ERROR"
      }
    }
  ]
}
SELECT
  table.publicId,
  DATE_TRUNC('hour', table.timestamp),
  MEASURE(
    table.temperature_status__igbt_temperature__c__max
  )
FROM
  table
WHERE
  ()
GROUP BY
  1,
  2
HAVING
  (
    MEASURE(
      table.temperature_status__igbt_temperature__c__max
    ) >= '0'
    AND MEASURE(
      table.temperature_status__igbt_temperature__c__max
    ) <= '2'
  )
LIMIT
  10000;
query temperature_status__igbt_temperature__c__max($timezone: String!, $fromDate: String!, $toDate: String!, $assets: [String!], $limit: Int!) {
  cube(
    timezone: $timezone
    where: {table: {
      id: {in: $assets}, 
      timestamp: {inDateRange: [$fromDate, $toDate]},
      temperature_status__igbt_temperature__c__max: {
        in: [0, 2]
      }
    }}
    orderBy: {table: {temperature_status__igbt_temperature__c__max: desc}}
    limit: $limit
  
  ) {
    table {
      id
      temperature_status__igbt_temperature__c__max
    }
  }
}

To Reproduce
Steps to reproduce the behavior:

  1. Deploy the minimal schema
  2. Execute the above GraphQL query, or go to the playground and try the non-GraphQL query, results will be the same: http://localhost:4000/#/build?query={%22measures%22:[%22table.temperature_status__igbt_temperature__c__max%22],%22dimensions%22:[%22table.publicId%22],%22filters%22:[{%22values%22:[%220%22],%22member%22:%22table.temperature_status__igbt_temperature__c__max%22,%22operator%22:%22gte%22},{%22values%22:[%222%22],%22member%22:%22table.temperature_status__igbt_temperature__c__max%22,%22operator%22:%22lte%22}]}
  3. Notice the HAVING error with the malformed SQL statement

Expected behavior
Should be able to filter on measures and not just dimensions. Surprisingly, the Playground lets you attempt this, implying that this should be possible.

Screenshots

Image Image

Minimally reproducible Cube Schema
In case your bug report is data modelling related please put your minimally reproducible Cube Schema here.
You can use selects without tables in order to achieve that as follows.

const sql_table = `"table"`;

cube("Table", {
  data_source: `table`,
  sql_table,

  pre_aggregations: {
    lambda: {
      type: `rollup_lambda`,
      rollups: [CUBE.batch],
    },
    batch: {
      refresh_key: {
        sql: `SELECT MAX(updated_at) FROM ${sql_table}`,
        every: `5 minute`,
      },
      measures: [
        CUBE.temperature_status__igbt_temperature__c__max,
      ],
      dimensions: [CUBE.id],
      time_dimension: CUBE.timestamp,
      granularity: `day`,
      partition_granularity: `day`,
      build_range_start: {
        sql: `SELECT MIN(timestamp) FROM ${sql_table}`,
      },
      build_range_end: {
        sql: `SELECT MAX(timestamp) FROM ${sql_table}`,
      },
    },
  },

  measures: {
    count: {
      type: `count`,
    },
    temperature_status__igbt_temperature__c__max: {
      sql: `ROUND(${CUBE}."temperature_status__igbt_temperature__c__max", 2)`,
      type: `max`,
    },
  },

  dimensions: {
    id: {
      sql: `${CUBE}.id`,
      type: `string`,
    },
    publicId: {
      sql: `ltrim(${CUBE}.id)`,
      type: `string`,
    },
    timestamp: {
      sql: `${CUBE}.timestamp`,
      type: `time`,
    },
    temperature_status__igbt_temperature_measure__c__max: {
      sql: `${CUBE}.temperature_status__igbt_temperature__c__max`,
      type: `number`,
    },
  },
});

Version:
Bug is present on both the latest v1.5.3, and v1.3.50

Additional Context
Using the playground, here is what is generated and run using the playground query builder.

Generated SQL

SELECT
  ltrim("table".id) "table__public_id",
  max(
    ROUND(
      "table"."temperature_status__igbt_temperature__c__max",
      2
    )
  ) "table__temperature_status__igbt_temperature__c__max"
FROM
  "jupiter__stgall2__hourly" AS "table"
GROUP BY
  "table__public_id"
HAVING
  (
    max(
      ROUND(
        "table"."temperature_status__igbt_temperature__c__max",
        2
      )
    ) >= $ 1
  )
  AND (
    max(
      ROUND(
        "table"."temperature_status__igbt_temperature__c__max",
        2
      )
    ) <= $ 2
  )
ORDER BY
  "table__temperature_status__igbt_temperature__c__max" DESC
LIMIT
  100000

SQL API

SELECT
  table.publicId,
  MEASURE(
    table.temperature_status__igbt_temperature__c__max
  )
FROM
  table
WHERE
  ()
GROUP BY
  1
HAVING
  (
    MEASURE(
      table.temperature_status__igbt_temperature__c__max
    ) >= '0'
    AND MEASURE(
      table.temperature_status__igbt_temperature__c__max
    ) <= '2'
  )
LIMIT
  100000;

REST API

{
  "measures": [
    "table.temperature_status__igbt_temperature__c__max"
  ],
  "dimensions": [
    "table.publicId"
  ],
  "filters": [
    {
      "values": [
        "0"
      ],
      "member": "table.temperature_status__igbt_temperature__c__max",
      "operator": "gte"
    },
    {
      "values": [
        "2"
      ],
      "member": "table.temperature_status__igbt_temperature__c__max",
      "operator": "lte"
    }
  ]
}

GraphQL API

query CubeQuery {
  cube(
    where: {table: {AND: [{temperature_status__igbt_temperature__c__max: {gte: 0}}, {temperature_status__igbt_temperature__c__max: {lte: 2}}]}}
  ) {
    table {
      temperature_status__igbt_temperature__c__max
      publicId
    }
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions