---
schema_version: "1"
id: b090efa8e68173f0e0ea60e851835309de624c65388343909715cd4bbb3da55c
title: CRM Analytics Apex Query
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/analytics/bi_dev_guide_sdk/guides/bi-sdk-apex-query.md
canonical_url: https://developer.salesforce.com/docs/analytics/bi-dev-guide-sdk/guide/bi-sdk-apex-query.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: 373fc14560c03c1e72eb5baa41674e9ab8e887c5ab549ce0c1825d5ed10896b9
products:
  - Analytics SDK Developer Guide
  - analytics
---

# CRM Analytics Apex Query

Query your data in CRM Analytics from any Apex class. Construct well-formed queries using the query builder.

The Apex SDK query features include the `executeQuery` method and the `Wave.QueryBuilder` class.

`ConnectApi.Wave.executeQuery`

At its simplest, use the `executeQuery` function (exposed through the ConnectApi namespace) to pass a SAQL query from an Apex page to CRM Analytics, and get a response in the form of JSON. For example, this sample sends ‘your SAQL query’ to CRM Analytics.

```nolang
String query = '[your SAQL query]';
   ConnectApi.LiteralJson result =  ConnectApi.Wave.executeQuery(query);
   String response = result.json;
```

Sending queries like this is useful, but relies on the developer coding well-formed SAQL queries. Wouldn’t it be great if a class constructed the queries for you?

`Wave.QueryBuilder`

The `Wave.QueryBuilder` class is the most convenient, preferred, and safest way to construct a SAQL query string for execution. It’s not an exhaustive implementation of all possible SAQL queries—so sometimes you must write your own—but it does cover the vast majority of use cases, including:

- load dataset statement

- foreach statement

- group statement

- order statement

- limit statement

- filter statement

- functions such as min, max, count, avg, unique, as, sum

Use `Wave.QueryBuilder` and its associated classes, `Wave.ProjectionNode` and `Wave.QueryNode`, to incrementally build your SAQL statement. For example:

```nolang
Wave.ProjectionNode[] projs = new Wave.ProjectionNode[]{
   Wave.QueryBuilder.get('State').alias('State'),
   Wave.QueryBuilder.get('City').alias('City'),
   Wave.QueryBuilder.get('Revenue').avg().alias('avg_Revenue'),
   Wave.QueryBuilder.get('Revenue').sum().alias('sum_Revenue'),
   Wave.QueryBuilder.count().alias('count')};
   ConnectApi.LiteralJson result = Wave.QueryBuilder.load('0FbD00000004DSzKAM', '0FcD00000004FEZKA2')
   .group(new String[]{'State', 'City'})
   .foreach(projs)
   .execute('q');
   String response = result.json;
```
