Skip to main content

BQL Keywords

This article details the basic keywords in Brinqa query language (BQL) that make up the clauses of a query statement, including sorting and pagination.

Before you begin to write Brinqa queries, note the following:

  • Wildcards (*) are only supported for the LIKE and NOT LIKE string functions.

  • The names of the data models in the queries are case sensitive, but keywords are not case sensitive.

  • String must be wrapped in double quotes ("string").

  • Boolean, Number, and Date values do not have to be wrapped in double quotes.

Basic keywords

The following keywords make up the clauses of a query statement to perform various operations:

note

Keywords are not case sensitive in BQL, but they appear in uppercase letters in the examples to differentiate with other parts of the query.

FIND

The FIND clause searches for an existing property or pattern in your data. It is followed by a data model. For example, the following query returns all vulnerabilities:

FIND Vulnerability

The above query is not specific and may not return useful results. To be more precise, you can add additional clauses to the query. See WHERE, THAT, and WITH.

AS

The AS clause defines an aliased selector to be referenced in the WHERE or RETURN clause. An alias only exists for the duration of the specific query. For example, the following BQL statement creates an alias, f, for Finding and returns all findings with a critical risk rating:

FIND Finding AS f WHERE f.riskRating = "Critical"

You can create multiple aliases for different data models in a query as long as the two data models have a relationship. For example:

FIND Finding AS f THAT HAS Asset AS a WHERE f.severity = "Critical" AND a.status = "Confirmed active"

The above query creates an alias, f, for Finding and also an alias, a, for Asset and returns all critical findings on active assets.

For information about how to view data model relationships, see examine relationships between data models.

WHERE

The WHERE clause adds constraints to the query and allows you to define specific criteria so you can find the exact data that you want to work with. WHERE is followed by an attribute that must exist on the target model. For example, the following query returns all users whose first name starts with "W":

FIND Person AS p WHERE p.firstName STARTS WITH "W"

The firstName attribute exists on the Person data model, so the query runs successfully.

The following query returns all active findings with a medium severity level:

FIND Finding AS f WHERE f.status = "Confirmed active" AND f.severity = "Medium"

Both the status and severity attribute exist on the Finding data model, so the query runs successfully. Check the data model reference for attributes and additional information.

THAT

The THAT keyword must be followed by a relationship verb such as BELONGS, CONTAINS, HAS, IS, RELATES, SUPPORTS, etc. For more information on relationships and BQL, see query for relationships in BQL.

tip

In BQL, prepositions such as IN, ON, AT, TO, or BY can be used after relationship keywords for fluidity, but they are ignored in terms of query processing. Thus, RELATES TO and RELATES are functionally identical.

The relationship verbs are not case sensitive and you can use the relationship verb to reference any relationship between two data models. For example, the following query returns all hosts with vulnerabilities:

FIND Host AS h THAT HAS Vulnerability AS v

You can take the previous example and go a step further by returning all hosts with critical vulnerabilities:

FIND Host AS h THAT HAS Vulnerability AS v WHERE v.severity = "Critical"

Relationship verbs are bidirectional. For example, the following queries are both valid:

FIND Asset AS a THAT HAS Vulnerability AS v
FIND Vulnerability AS v THAT HAS Asset AS a

Furthermore, you can use RELATES TO or RELATES to express a relationship between data models without specifying or needing to know the exact name of the relationship.

For example, either of the following queries can be used to find Vulnerability records that contain any type of relationship with VulnerabilityDefinition:

FIND Vulnerability as v THAT RELATES TO VulnerabilityDefinition as v2

FIND Vulnerability as v THAT RELATES VulnerabilityDefinition as v2

On the other hand, the following query retrieves records where Vulnerability has a defined IS relationship with VulnerabilityDefinition:

Find Vulnerability as v THAT IS VulnerabilityDefinition as v2

While RELATES TO and RELATES offer broader query results, covering any relationship type, specific keywords like IS provide more targeted results based on a known relationship type.

RETURN

The RETURN clause lets you define what you want to include in the query's result set. This can make your data more relevant by reducing unnecessary data and focusing on specific assets or properties.

note

You can only use RETURN in reports, automations, and in explorer graphs. It is ignored in list views for assets, findings, or tickets. Additionally, you can only return the id attribute in automations.

For example, when used in a report, the following query returns a number of unique vulnerabilities:

FIND Vulnerability AS v RETURN DISTINCT count(*)

This query is useful when you need to know the total count of unique vulnerabilities in your dataset. By using DISTINCT count(*), you ensure that each vulnerability is only counted once, giving you an accurate count.

When using the RETURN clause in automations, make sure to return only the id attribute to avoid your automation failing. If your query involves one-to-many relationships, you can get duplicated records unless you add RETURN DISTINCT <alias>.id to the end of the query.

For example, the following query can be used in automation to get a list of unique user IDs and their associated remediation owner IDs:

FIND User AS u THAT OWNS RemediationOwner AS ro THAT OWNS_REMEDIATION Finding AS f WHERE f.severity = "High" RETURN DISTINCT u.id, ro.id

In the above query, User and RemediationOwner have a one-to-many relationship. By returning DISTINCT u.id, you ensure that only unique user IDs are returned, preventing duplicates.

WITH

The WITH clause allows parts of the query statement to be tethered together, connecting the results from one to be used as starting points or criteria in the next. For example, the following query returns hosts with vulnerabilities in ascending order:

FIND Vulnerability AS v THAT HAS Host AS h WITH v, h.displayName AS order ORDER BY order ASC

Multi-labeling

You can use the pipe symbol | to query for different data models that share similar attributes. This is called Multi-labeling. For example, the following query returns all hosts and vulnerabilities that are sourced from the Qualys Vulnerability Management connector:

FIND Host|Vulnerability WHERE connectorNames = "Qualys Vulnerability Management"

The connectorNames attribute exists on both Host and Vulnerability, allowing this query to work across both data models. In addition, the pipe symbol | is used between the two data models to combine them in a single query.

The above query is less complex and time-consuming than running multiple queries to achieve the same result. For example, the following two queries retrieve the same number of hosts and vulnerabilities from Qualys, but the process is more time-consuming as you must run two separate queries:

FIND Host AS h WHERE h.connectorNames = "Qualys Vulnerability Management"
FIND Vulnerability AS v WHERE v.connectorNames = "Qualys Vulnerability Management"

Sorting and Pagination

You can sort and page through your data by utilizing the ORDER BY, SKIP, and LIMIT subclauses in BQL. Sorting arranges records in either ascending or descending order to provide a more concise view, and pagination reduces the number of records returned from a query.

ORDER BY

You can use the ORDER BY sub-clause to sort the queried data in either ascending or descending order. To sort the results in ascending order, use ASC; and for descending order, use DESC.

ORDER BY is followed by an expression or field to indicate how to sort the data. For example, ORDER BY riskRating DESC, sorts the records by their risk ratings in descending order.

SKIP

The SKIP keyword is followed by a number to indicate how many records to skip in the output. For example, SKIP 20, skips the first 20 records and returns the queried data from the 21st record.

LIMIT

The LIMIT keyword is followed by a number to limit the number of records to return. For example, LIMIT 5, returns five records from the queried data.

note

You can only use SKIP and LIMIT in reports, automations, and in explorer graphs. SKIP and LIMIT are ignored in all list views.

The following example uses ORDER BY, SKIP, and LIMIT in a query together to demonstrate sorting and pagination:

FIND Asset AS a ORDER BY a.riskRating DESC SKIP 20 LIMIT 5

The above query retrieves assets from your data, sorts them in descending order by their risk ratings, skips the first 20 records, and then limits the result to 5 records, returning the 21st through 25th records from the sorted list.

note

If LIMIT is not set in the query, it could result in a large number of records to return.

CASE statements

CASE statements enable you to perform conditional evaluations within your queries. It evaluates conditions sequentially and returns a result based on the first condition met. If none of the conditions are met, the ELSE clause provides a default result.

CASE statements in BQL follow the same logic as CASE expressions in Neo4j and SQL. For additional information, see SQL CASE documentation and Neo4j CASE documentation.

note

CASE statements can only be used with the RETURN keyword. It is limited to reports, automations, and explorer graphs, and is ignored in list views for assets, findings, or tickets.

The following BQL query uses a CASE statement to categorize vulnerabilities based on their compliance status:

FIND Vulnerability AS v 
RETURN
CASE
WHEN v.complianceStatus IN ["Met SLA", "Within SLA"] THEN "Compliant"
WHEN v.complianceStatus IN ["Out of SLA", "Exceeded SLA"] THEN "Not Compliant"
ELSE "No Value"
END AS "Compliance Status",
count(*) AS Count

Let's break down the components of the above BQL query to better understand how the CASE statement is constructed and interpret the results:

  1. FIND Vulnerability AS v RETURN:

    • Retrieves records from the Vulnerability data model, assigns the alias v, and RETURN specifies the data to be returned.
  2. CASE

    • CASE marks the start of a conditional block that evaluates conditions (WHEN clauses) in sequence, returning the result of the first match.
  3. WHEN v.complianceStatus IN ["Met SLA", "Within SLA"] THEN "Compliant"

    • WHEN checks if v.complianceStatus is either "Met SLA" or "Within SLA" and returns "Compliant" if true.
  4. WHEN v.complianceStatus IN ["Out of SLA", "Exceeded SLA"] THEN "Not Compliant"

    • WHEN checks if v.complianceStatus is either "Out of SLA" or "Exceeded SLA" and returns "Not Compliant" if true.
  5. ELSE "No Value"

    • ELSE defines the default result and returns "No Value" if none of the WHEN conditions are met.
  6. END AS "Compliance Status"

    • END marks the conclusion of the CASE block and assigns the alias "Compliance Status" to the result.
  7. count(*) AS Count

    • Counts the number of matching records and assigns the alias "Count".

The following screenshot illustrates the results of the BQL query in a tabular report section using the advanced mode. Each row represents a compliance status category, showing the total count of vulnerabilities based on the CASE statement WHEN conditions, grouped as either "Compliant" or "Not Compliant."

BQL CASE statement example