BQL Basics

The Logical Query Language (BQL) includes various pieces of functionality.

Basic Elements and Query Syntax

There are two basic elements in Birst visualizations and dashboards: attributes and measures. They correspond to hierarchy (dimension) attributes and fact columns in the underlying data model. BQL uses attributes and measures to generate query results.
Note: The terms "attribute" and "measure" are from the realm of data warehousing. If you are familiar with spreadsheets or relational databases, attributes and measures are two different kinds of columns. Attributes contain descriptions or the names of "things". Measures are columns containing numeric data most commonly used in calculations and used in aggregate functions (i.e., SUM, AVG). As you write and see the results of BQL queries and expressions, the meanings of these terms become more evident.

The basic form of a BQL query is:

SELECT [attribute],[measure] FROM [subject_area] WHERE condition ORDER BY [attribute|measure] ASCENDING|DESCENDING

You can select one or more attributes or measures from a given subject area, filter results, and sort them.

BQL syntax requires that attribute, measure, and subject area names are surrounded by square brackets. Strings are surrounded by single quotes.

A subject area is a grouping of attributes and measures in the space. The default subject area is “ALL”, which indicates the entire set. Most BQL statements use [ALL]. For ease of use or security reasons, you may create a custom subject area having a subset from the entire list. See Creating and managing a subject area in the Infor Birst Administrator User Guide.

This is an example of a basic BQL query:

SELECT [Order_Date: Sum: Quantity], [Products.Products] FROM [ALL] WHERE [Order_Date: Sum: Quantity]>=50000 ORDER BY [Order_Date: Sum: Quantity] DESCENDING

To put comments in BQL code, use this syntax:

/* my comment */

  • Syntax and Conventions for Examples
    • These are the conventions followed in the examples:
      • Keywords are in ALL CAPS.
      • Pipes (|) separate multiple possible entries (attribute|measure means either an attribute name or a measure name).
      • Placeholders for element names are in italic font.
      • Optional elements are in curly brackets { }.
      • Most examples do not specify header strings.
      • Most examples use [ALL] as the subject area.
    • It is not required to write all queries by hand. You can use the Visualizer drag-drop interface to interactively build queries, then click Advanced Tools > Queries to see the BQL statement that was generated via drag and drop.
    • For advanced users with data warehousing experience, use Navigate Query in the Space Admin > Query Admin to see how the query engine executes the logical query against the physical tables. See Query Admin in the Infor Birst Administrator User Guide.

Hierarchy Attributes (Dimensional Attributes)

To create a query that includes a hierarchy column, use its fully qualified name, the column name preceded by the hierarchy name. For example, to select an attribute:

SELECT [hierarchy.attribute] FROM [subject_area]

For example, to select all categories of products:

SELECT [Products.Categories] FROM [ALL]

Table 1. Query Result
Categories
Desktop
MP3 Players
Mobile Phones
Notebooks
Tablets

Measures (Fact Columns)

The syntax for including measures in a query is similar to attributes. Because measures are for counting, they have additional functionality including aggregates and date type (Analyze by Date enablement in Prepare/Model Properties). Aggregates are required; date types are optional though strongly encouraged on those date columns where it is important to slice data by time series (i.e., YTD).

SELECT [{date_type: }aggregate: measure] FROM [ALL]

  • Aggregates for Measures
    • Aggregates are required in the SELECT statement and they are case-sensitive. Aggregates include:
      • Avg
      • Count
      • Count Distinct
      • Max
      • Min
      • Sum
    • For example:

      SELECT [Order_Date: Sum: Quantity] FROM [ALL]

      Table 2. Query Result
      Order_Date: Sum: Quantity
      2,833,776
    • Two special aggregates use a slightly different syntax. Count and Count Distinct use the hash sign (#) and do not use a colon:
      • # Distinct (count distinct)
      • # (count)
    • For example:

      SELECT [# Distinct Quantity] FROM [ALL]

      Table 3. Query Result
      # Distinct Quantity
      502

Data Types for Measures

For all measures there is a default. For many of the measures, there is an optional syntax for specifying a "by Date Type".

To specify a different "by Date Type", the measure must have one or more related date type columns in its data source. If the related date type columns are marked "Analyze by Date" in Modeler > Relate > Modeler > Model Properties, then Birst creates additional columns in the model that support querying by the date. For example, the Quantity measure has related Order_Date and Ship_Date columns that are enabled for analyzing Quantity by date. See Defining Column Properties in the Infor Birst Modeler User Guide.
Note: Modeler provides data aggregation based on the data you import. You will not have the option to set the analyze-by-date feature as described.

The default date type is Load Date, the last time the data source was loaded.

Note: Be sure to use the date type that makes sense for the particular measure and the calculation you want to create.

Use the date type syntax before the aggregate syntax:

SELECT [attribute],[{date_type: }aggregate: measure_name] FROM [ALL]

For example, by Order Date:

SELECT [Order_Date: Sum: Quantity] FROM [ALL]

Table 4. Query Result
Order_Date: Sum: Quantity
944,592

To ensure measures make sense in a visualization, include at least one attribute in the query.

Note: Hierarchy relationships are joined through a measure. Hierarchies are not directly related to each other.

For example, to analyze quantity by category:

SELECT [Products.Categories],[Order_Date: Sum: Quantity] FROM [ALL]

Table 5. Query Results
Categories Quantity
Desktop 74,485
MP3 Players 308,100
Mobile Phones 135.397
Notebooks 117,216
Tablets 309.394

Column Header Strings

The syntax for changing column headers is optional. By default Birst uses the column name from the data store as the header.

SELECT [attribute | measure {'header_string'}, attribute | measure {'header_string'} ...] FROM [subject_area]

For example, to change the column headers from Categories to Category and Quantity to Total:

SELECT [Products.Categories] 'Category', [Order_Date: Sum: Quantity] 'Total' FROM [ALL]

Table 6. Query Results
Categories Quantity
Desktop 74,485
MP3 Players 308,100
Mobile Phones 135.397
Notebooks 117,216
Tablets 309.394
  • Column Headers in Designer and Visualizer
    • When Designer automatically creates queries for you based on what you drag-and-drop, it uses internal syntax ('F1', 'F2', etc.) to map the header placeholder to the header from the data store, and it displays the header. In Designer you do not use BQL to change the headers, instead you click on the column header and select Label Properties to modify the column label.
    • Visualizer does the same, though it uses 'COL0', 'COL1', etc. as the placeholder. You can see this for a report's query at Visualizer > Advanced Tools > Queries. To change headers in Visualizer, double-click on the column label in a table or on the axis label text on a chart.

Filtering Results: WHERE

In addition to selecting attributes and measures, you can restrict the results to various subsets using a WHERE clause.

For example, if you want to know the sales for 2014:

SELECT [Order_Date: Sum: Unit_Sale_Price] 'Sum of Unit Sale Price in 2014' , FROM [ALL] WHERE [Time.Year]=2014

Table 7. Query Result
Sum of Unit Sale Price in 2014
14,594,869.03
The filter column does not have to be one of the SELECT columns. A WHERE clause can include any attribute filtered for any specific value. Filtering operators include:
  • = (equals)
  • > (greater than)
  • < (less than)
  • >= (greater than or equals)
  • <= (less than or equals)
  • <> (not equals)

For example:

SELECT [Order_Date: Sum: Unit_Sale_Price] 'Sum of Sales Before 2014' , FROM [ALL] WHERE [Time.Year]<=2014

Table 8. Query Result
Sum of Unit Sale Price Before 2014
94,639,114.88
  • Filtering Results on Measure Values
    • You can restrict results based on measures. For example, to see a list of products that sold at least 50000 units in 2014:

      SELECT [Order_Date: Sum: Quantity] 'Quantity', [Products.Products] FROM [ALL] WHERE [Order_Date: Sum: Quantity]>=50000
      Table 9. Query Results
      Quantity Products
      103,445 mangoPad 3 32 GB
      94.946 mangoPad 3 64 GB
      105.703 mangoPhone 4G 32 GB
      65,229 mangoPad 3 64 GB

      The query returns only the records where the measure column matches the filter when grouped by the attributes in the query.

  • Using Multiple Filters: AND, OR
    • More complicated queries can combine several individual filters using AND and OR syntax. For example, to see a list of products that sold at least 50000 units in 2014:

      SELECT [Order_Date: Sum: Quantity] 'Quantity', [Products.Products] FROM [ALL] WHERE [Order_Date: Sum: Quantity]>=50000 AND [Time.Year] = 2014
      Quantity Products
      50,117 mangoPhone 4G 32 GB

      You can add an OR clause and use parenthesis to indicate which AND or OR takes precedence:

      SELECT [Order_Date: Sum: Quantity] 'Quantity', [Products.Products] FROM [ALL] WHERE [Order_Date: Sum: Quantity]>=50000 AND ([Time.Year] = 2014 OR [Time.Year] = 2013)
      Table 10. Query Results
      Quantity Products
      103,445 mangoPad 3 32 GB
      105,703 mangoPhone 4G 32 GB
      65,229 mangoPhone 4G 64 GB
      94,946 mangoPad 3 64 GB
  • Filtering a Single Measure
    • In addition to filtering an entire result set, it is often useful to be able to filter specific measures by an attribute. This is also called a measure filter. An example is to show Quantity for all sales and only for sales in France. To calculate this, you add a WHERE clause to the measure section, instead of after the FROM clause:

      SELECT [Order_Date: Sum: Quantity] 'Quantity All', [Order_Date: Sum: Quantity] WHERE [Retail_Stores.Retailer Country]='France' 'France Only' FROM [ALL]

      Quantity All France Only
      944,592 3,352

      Only filters on attributes are allowed in a measure filter. This is because a measure is undefined without a level of aggregation. If you want to filter based on a measure at a given level, you can use bucketed measures that turn measures into attributes with values bucketed based on the measure. This will make certain what level of aggregation is applied to a measure before it is applied in a measure filter.

  • Filtering on a Measure-Filtered Column
    • Occasionally, you would like to filter a result set based on a filtered measure column. The syntax to do this is a slight alteration of both the normal filter syntax and the measure filter syntax. The filtered measure is surrounded by parenthesis to indicate that this is a measure filter.

      SELECT [Time.Year/Quarter], [Products.Categories], [Order_Date: Sum: Quantity] 'Quantity', FROM [ALL] WHERE ([Order_Date: Sum: Quantity] WHERE [Products.Categories]='Tablets')>=25000

      Table 11. Query Results
      Year/Quarter Categories Quantity
      2013/Q1 Tablets 35,284
      2013/Q2 Tablets 45,466
      2013/Q3 Tablets 33,849
      2013/Q4 Tablets 25,436
      2014/Q1 Tablets 45,848
      2014/Q2 Tablets 41,534
  • Set-Based Filtering: IN, NOT IN
    • You can create a subquery that defines a set of values used to filter the parent query. This allows for more complex filtering conditions. For example:
      SELECT [Products.Products],[Order_Date: Sum: Quantity] FROM [ALL] WHERE [Products.Categories] IN (SELECT [Products.Categories] FROM [ALL] WHERE [Order_Date: Sum: Quantity]<=100000)
      Table 12. Query Results
      Products Order_Date: Sum: Quantity
      iMango Desktop 22 15,439
      iMango Desktop 27 12,823
      iMango Mini 3.0 GHz 3,348
      iMango Mini 3.5 GHz 11,810
      Mango Server 5,211
      Mango Workstation 12 Core 2,355
      Mango Workstation 8 Core 10,003
      Mango Workstation Quad Core 13,496

      In this example the filtering is done on Products.Categories, which is not displayed, and all the Products in the category that meets the criteria are displayed.

      Note: BQL expressions that perform operations, including query functions (RANK, CONCAT, etc.) and positional calculations, in subqueries are not supported. The "IN" or "NOT IN" subquery can use the basic operators such as equal to (=), less than (<), etc.
      Note: Designer supports set-based filters. Visualizer does not.
  • Date Syntax in Filters
    • You may need to refer to a specific date in a BQL query WHERE filter. For slash-style dates, add the hash sign around the string. For example:

      ...WHERE [Month.Start Date]=#11/1/2015#

Controlling Sort Ordering: ORDER BY

You can specify how results should be sorted by attribute orderings or measure orderings. Sorts can be either ASCENDING or DESCENDING. The abbreviated syntax ASC and DESC are also supported.

For example, to show product categories in descending order of sales:

SELECT [Order_Date: Sum: Quantity], [Products.Categories] FROM [ALL] ORDER BY [Order_Date: Sum: Quantity] DESCENDING
Table 13. Query Results
Order_Date: Sum: Quantity Categories
309,394 Tablets
308,100 Mobile Phones
135,397 MP3 Players
117,216 Notebooks
74,485 Desktops

You can define multiple sorts. For example, to sort by store region, then by quarter for 2013:

SELECT [Order_Date: Sum: Quantity], [Retail_Stores.Retail Region], [Time.Quarter] FROM [ALL] WHERE [Time.Year]='2013' ORDER BY [Retail_Stores.Retail Region] ASC, [Time.Quarter] DESC

Returning a Limited Result Set: TOP

Use the TOP operator to return a limited number of rows in the result set from the database.

For example:

SELECT TOP 5 [Order_Date: Sum: Quantity], [Products.Products] FROM [ALL] ORDER BY [Order_Date: Sum: Quantity] ASCENDING

Table 14. Query Results
Order_Date: Sum: Quantity Products
1,218 Mango Air 11 128GB
1,623 MangoBook Pro 15 3.5 GHz
2,355 Mango Workstation 12 Core
3,348 Mango Mini 3.0 GHz
4,525 MangoBook Pro 17 3.5 GHz

This example causes the query to return only the top 5 records, as determined by sort order.

Whatever sort ordering is applied, TOP limits the results to the first ones in the result set. For example, if you change the sort order to DESCENDING, the TOP would be very different.

SELECT TOP 5 [Order_Date: Sum: Quantity], [Products.Products] FROM [ALL] ORDER BY [Order_Date: Sum: Quantity] DESCENDING

Table 15. Query Results
Order_Date: Sum: Quantity Products
105,703 mangoPhone 4G 32GB
103,445 MangoBook Pro 15 3.5 GHz
94,946 Mango Workstation 12 Core
65,229 Mango Mini 3.0 GHz
48,641 MangoBook Pro 17 3.5 GHz
Note: The TOP operator is useful when you have a large result set and do not need to see all the rows, or you want to improve performance.
Note: By default, Visualizer uses the TOP operator to limit the return set to the top 100 rows. You can change the TOP setting by clicking the Top N Results button.

INNER and OUTER Joins: USING OUTER Join

Depending on the underlying data, you combine measures in a result set with the USING OUTER JOIN syntax.

By default, the BQL query engine returns only results that have values for all measures that are specified. This behavior generates more efficient underlying queries and conforms to standardized data warehousing techniques.

However, sometimes you want to include all dimensional attributes that have any cells filled, regardless of whether some measures have values. This is called an outer join and you employ the USING OUTER JOIN syntax. For example:

SELECT USING OUTER JOIN [Products.Categories], [Order_Date: Sum: Quantity], [Order_Date: Sum: Revenue] FROM [ALL]

Note: By default, Designer and Visualizer generate queries having the USING OUTER JOIN syntax.
Note: In formal data warehousing based on star schema, this is not a significant issue because all elements have a value for all periods (at the intersection of all dimensions, all cells in the cube are full) even if it is set to zero. However, because there may be no values for various dimensional attributes in practical warehousing where the underlying tables may be in a more normalized format, outer joins are required.

Constants

BQL supports string or numeric constants in queries. Surround strings in single quotes.

SELECT 'Test_Constant', [Order_Date: Sum: Quantity] FROM [ALL]

A string constant in the SELECT statement results in a column that includes the string in each row, including the header. For example:

Table 16. Query Results
Test_Constant Quantity
Test_Constant 150,028
Test_Constant 215,021
Test_Constant 330,081
Test_Constant 249,462

For more BQL syntax, see Advanced BQL.