(Incomplete) MBQL Reference
This guide is incomplete, and it is also out of date. Some features are missing or different, and others could use clarification. For an always up-to-date guide to the syntax of MBQL, check out https://github.com/metabase/metabase/blob/master/src/metabase/mbql/schema.cljc.
This guide is still useful to understand some of the design philosophy around MBQL, but should no longer be used as a grammar reference.
MBQL, the Metabase Query Language, is the language used to express "structured" queries in Metabase. It is generated by the Query Builder in the Metabase frontend, and translated into a myriad of "native" query languages -- including SQL, Mongo Aggregation Pipelines, and Druid -- by the backend. (Metabase can also run queries in these native languages directly, but those are not considered part of MBQL).
If you're new to MBQL or this document, please familiarize yourself with MBQL's core concepts, specifically the conventions used in the MBQL grammar and examples.
- {
:aggregation
aggregation-clause
}-
aggregation-clause:
- [
:avg
concrete-field
] - [
:count
] - [
:count
concrete-field
] - [
:count-where
filter-clause
] - [
:cum-count
concrete-field
] - [
:cum-sum
concrete-field
] - [
:distinct
concrete-field
] - [
:stddev
concrete-field
] - [
:sum
concrete-field
] - [
:sum-where
concrete-field
filter-clause
] - [
:min
concrete-field
] - [
:max
concrete-field
] - [
:share
filter-clause
]
- [
-
- {
:breakout
[&concrete-field
]} - {
:expressions
{expression-name
expression
}} - {
:fields
[&field
]} - {
:filter
filter-clause
}-
filter-clause
: - [
:and
&filter-clause
] - [
:or
&filter-clause
] - [
:not
filter-clause
] - [
:=
concrete-field
value
&value
] - [
:!=
concrete-field
value
&value
] - [
:<
concrete-field
orderable-value
] - [
:>
concrete-field
orderable-value
] - [
:<=
concrete-field
orderable-value
] - [
:>=
concrete-field
orderable-value
] - [
:is-null
concrete-field
] - [
:not-null
concrete-field
] - [
:between
concrete-field
minorderable-value
maxorderable-value
] - [
:inside
latconcrete-field
lonconcrete-field
lat-maxnumeric-literal
lon-minnumeric-literal
lat-minnumeric-literal
lon-maxnumeric-literal
] - [
:starts-with
concrete-field
string-literal
] - [
:contains
concrete-field
string-literal
] - [
:does-not-contain
concrete-field
string-literal
] - [
:ends-with
concrete-field
string-literal
] - [
:time-interval
fieldconcrete-field
n:current
|:last
|:next
|integer-literal
unitrelative-datetime-unit
]
-
- {
:limit
integer-literal
} - {
:order-by
[&order-by-clause
]}-
order-by-clause
:- [direction
:asc
|:desc
fieldfield
]
- [direction
-
- {
:page
{:page
integer-literal
,:items
integer-literal
}} - {
:source-table
integer-literal
}
For the most part, this document uses Clojure in the examples and its terminology and syntax.
- Literal
:tokens
are written in monospaced font with a preceding:
. In queries, you may pass these tokens as either strings or Lisp keywords. See the conceptual explanation of tokens for more information. - parameter-names are used in certain cases for clarification.
- optional varargs are written as in a Clojure binding, using
&
-
Maps/dictionaries/hashes/associative arrays are written in Clojure syntax, e.g.
{:key "value"}
For example, a grammar like this:
- [
:=
fieldconcrete-field
valuevalue
& additional-valuesvalue
]
Could correspond to one of these clauses in real life:
[:= [:field-id 5] 100]
["=" ["field-id" 5] 100 200]
In examples, ->
is used to denote the output of a query or expression, especially in cases where an expression is automatically translated to another form.
<angle-brackets>
are used for clarity to represent arguments to expressions instead of giving literal values like in the previous example:
[:= <field> <v1> <v2>]
-> [:or [:= <field> <v1>]
[:= <field> <v2>]]
Tokens are literal keywords (in the Lisp/Ruby sense) or strings in MBQL and have special meaning, much like keywords in a programming language. You'll usually see them at the beginning of a bracketed expression:
[:= <field> <value>] ; := is a token
When writing a query, you may use either Clojure keywords or strings for tokens. Tokens are also case-insensitive and lisp-case
/snake_case
insensitive.
For example, these query fragments are all understood to be the same thing:
{:source_table 100}
{:source-table 100}
{"SOURCE_TABLE" 100}
{"source_table" 100}
In the examples in this document, tokens are written in a monospaced font with a preceding colon, like :lisp-keywords
. For consistency, all tokens are written in (lower-case)
lisp-case
.
Most of the forms in MBQL '98 look something like:
[:= [:field-id 100] "COOL"]
It may be helpful to think of MBQL as a square-bracketed LISP; indeed, this is how such expressions are internally implemented. The expression above becomes a function call like:
(= (field-id 100) "COOL")
The parameters to MBQL's square-bracked funcalls are rvalues in the C++ sense:
An rvalue is a temporary value that does not persist beyond the expression that uses it.
An rvalue is either a field reference
or a literal value
.
A field reference rvalue is a concrete reference to a metabase.models.field/Field
(such as its ID
) or some
derivative calculation thereof (an expression reference), or an aggregate field reference to one of the fields
produced by the query's aggregation being performed, such as :count
.
A concrete Field reference refers to a column represented internally by a metabase.models.field/Field
.
All columns in a database are mapped to Fields
on the backend, so a
concrete Field reference effectively means any existing column in the database (as opposed to one generated as the result of a query, such as a count
column
returned when doing an aggregation
). You can think of a concrete field as any column that would come back when doing a SQL SELECT(*)
query.
A field reference may be local
or foreign
, optionally wrapped by a datetime-field
form; for most intents and purposes, a
expression reference is also considered a "concrete field" and may be used in the same places.
Local field references are the most common type of field references. Local simply means that the Field
being referenced belongs to a query's source table
(as opposed to a different Table in the Database).
Local field references look like:
- [
:field-id
integer-literal
]
e.g.
[:field-id 100] ; the metabase.models.Field whose ID is 100
In older versions of MBQL, raw integer literals were used for local field references. This caused ambiguity with integer literals in certain clauses, so each clause assumed certain argument positions were always field references, while others were always assumed to be values. As such, in older versions of MBQL it was impossible to include multiple Fields in a single filter clause:
;; MBQL '98
{:filter [[:= [:field-id 10] [:field-id 11]]]} ; return rows where Field 10 == Field 11
;; MBQL '95
{"filter" [["=" 10 11]] ; Oops! Return rows where Field 10 == 11
MBQL '98 eliminates this ambiguity in order to relax the restrictions on where Fields can be used in filter clauses.
Foreign field references are just like local references, but are used to refer to Fields
belonging to a Table
other than
the source table. Access to these Fields requires JOINS
to their parent Table. To avoid ambiguity when
performing the join, you must specify a Field belonging to the source Table that is a foreign key to use to perform the join.
Foreign field references look like:
- [
:fk->
fk-field-idinteger-literal
, dest-field-idinteger-literal
]
ex.
;; Order by Field 20, which belongs to a different Table. Join to its Table via Field 10, which belongs to the source Table.
{:order-by [[:asc [:fk-> 10 20]]}
It may be helpful to think of the form as suggesting you access dest-field-id through fk-field-id.
The Field with fk-field-id must have a corresponding metabase.models.ForeignKey
instance, which should be created automatically during the sync process. For obvious reasons,
databases that don't support joins cannot use foreign field references; drivers that do support them declare the feature :foreign-keys
.
- [
:datetime-field
local-field-reference
|foreign-field-reference
datetime-unit
]
Datetime Fields
wrap a datetime field and specify how its values should be bucketed. Datetime fields used without being wrapped in a datetime-field
form are automatically converted to datetime-field
forms with :day
bucketing for legacy backward-compatibility reasons. This is not usually what you want, so be sure to use the :datetime-field
form to pick the bucketing you'd like!
datetime-field
forms can be used anywhere you can otherwise use a local
or foreign
field reference.
;; Row count broken out by Field 20, grouped by day (the default)
{:aggregation [:count]
:breakout [[:field-id 20]]}
;; Row count broken out by Field 20, grouped by year
{:aggregation [:count]
:breakout [[:datetime-field [:field-id 20] :year]]}
Older versions of MBQL required an AS
in the datetime-field
form in a misguided
attempt to improve readability, e.g.:
;; MBQL '95
["datetime_field" 100 "as" "week-of-year"]
This parameter should be considered deprecated now that MBQL has been re-envisioned as a square-bracketed Lisp. MBQL '98 will currently accept the older syntax, albeit begrudgingly.
An aggregate field reference refers to one of the fields produced by the query's aggregation, such as :count
. It has the form:
- [
:aggregation
indexinteger-literal
]
index is the index of the aggregation
in question. Since MBQL current only supports a single aggregation clause, index currently must always be zero.
aggregate-field
clauses are primarily used for ordering results:
{:aggregation [:sum [:field-id 10]]
:breakout [[:field-id 20]]
:order-by [[:desc [:aggregation 0]]} ; order by sum, descending
- [
:expression
expression-namestring-literal
]
An expression reference refers to one of the expressions added to the query. Suppose you have an :expressions
clause like this:
{:expressions {:sales_tax [:- <id of total> <id of subtotal>]}}
You can refer to this expression elsewhere in the query, e.g. in the :order-by
clause:
{:order-by [[:desc [:expression :sales_tax]]]} ; sort results of the query by the value of (total - subtotal)
For purposes of this grammar an expression reference can be considered a concrete field reference and used anywhere one is accepted. The sole exception is within the :expressions
clause itself, where expression references aren't allowed.
A value can be nil
, a boolean (true
or false
), a string literal
, a numeric literal
, or a datetime literal
.
Values are used in filter clauses
to restrict the results returned by a query. Some filter clauses, like =
, can accept any type of
value; others are more restrictive, and only accept certain types of values. Several filters such as <
only accept values that are considered
orderable, i.e. numbers and datetimes.
A (presumably UTF-8 encoded) string literal. Implemented internally as a java.lang.String
.
"I'm a string literal!😋"
An orderable value is something that makes sense in comparisons like <
-- either a numeric literal
or a datetime literal
.
[:= <field> true] ; makes sense
[:< <field> true] ; doesn't make sense -- values of a field cannot be "less than" true
[:< <field> 100] ; makes sense, values of a field can be less than 100
Either integer literals
or floating-point literals
.
A integer. Internally, these are represented java.lang.Integer
, which is 32-bit; thus MBQL integers cannot be
less than -231 or greater than 231-1.
A double-precision floating point number. Internally, these are represented by java.lang.Double
.
A datetime literal represents a moment in time, either absolute or relative to the moment the query is ran.
- To represent an absolute moment in time, use an ISO-8601 formatted string. In Clojure, you may also use a
java.sql.Date
or one of its subclasses, such asjava.sql.Timestamp
. - To represent a moment in time relative to when the query is ran, use a
relative-datetime form
.
ISO-8601 formatted strings are used to represent an absolute moment in time.
Some examples of valid ISO-8601 strings:
"2014"
"2014-09"
"2014-09-21"
"2015-09-20T19:31"
"2015-09-20T19:31:36"
"2015-09-20T19:31:36Z"
"2015-09-20T19:31:36.000"
"2015-09-20T19:31:36.000Z"
"2015-09-20T19:31:36.000+00:00"
Some QP code actually parses datetime strings according to RFC 3339, which is basically a subset of ISO 8601. You probably won't need to worry about the differences between the two; almost every string valid in format is valid in the other. ISO-8601 is a much more widely-known standard than RFC 3339; for the sake of familiarity the rest of this document only specifically mentions the former.
Relative datetimes represent a point in time relative to each moment the query is ran, such as today or 1 year ago. A relative datetime is expressed as one of the following forms:
- [
:relative-datetime
:current
] - [
:relative-datetime
ninteger-literal
unitsrelative-datetime-unit
]
The first form represents the moment in time a query is ran. It is analogous to the SQL NOW() function.
The second form represents a moment in time n
units
from the moment the query is ran. For example, you could express 31 days ago as follows:
[:relative-datetime -31 :day]
Valid units for a relative datetime form are:
:minute
:hour
:day
:week
:month
:quarter
:year
Subtraction and addition of units are done simply; in other words, -2 :day
is the same as -48 :hour
or -2880 :minute
.
These units are used to specify the desired bucketing of fields with the datetime-field
form. Bucketing, as used in this document,
refers collectively to both datetime truncation and extraction operations. Truncation operations are flooring operations that convert values to a lower resolution (such as
the start of the current day or of the current month); extraction operations extract some element of a date (such as the month) without regard to other elements.
Truncation is analogous to date_trunc
in Postgres, while extraction is analogous to
extract
.
Token | Operation | Example | Description |
---|---|---|---|
default | N/A | 2016-02-01 21:59:20 | No bucketing should take place -- use the default resolution of the column in question, such as seconds or milliseconds. |
minute | truncation | 2016-02-01 21:59 | Truncate to the beginning of the current minute. |
minute-of-hour | extraction | 59 | The minute of the the current hour. Ranges from 0 - 59. |
hour | truncation | 2016-02-01 21:00 | Truncate to beginning of the current hour. |
hour-of-day | extraction | 21 | Extract the current hour. Ranges from 0 - 23. |
day | truncation | 2016-01-01 | Truncate to the beginning of the current day. |
day-of-week | extraction | 2 [Monday] | Day of week, with Sunday as the first day of the week (1) to Saturday(7) |
day-of-month | extraction | 1 | The calendar date. |
day-of-year | extraction | 32 | Day of the year, with January 1st the first day (1). |
week | truncation | 2016-01-31 | Truncate to the beginning of the week (Sunday). |
week-of-year | extraction | 6 | Week of the year with the week containing January 1st as week 1. |
month | truncation | 2016-02 | Truncate to the first day of the month. |
month-of-year | extraction | 2 [Feb] | Extract the month of the year as you'd see on a calendar (e.g. January is 01). |
quarter | truncation | 2016-01-01 | Truncate to the beginning of the quarter. Quarters start on Jan 1st, April 1st, July 1st, and October 1st of each year. |
quarter-of-year | extraction | 1 | The number of the current quarter (1-4), with the quarter beginning Jan 1st as 1. |
year | extraction | 2016 | Extract the current year. |
An aggregation
is analogous to SQL aggregation functions like COUNT()
or SUM()
. When specified, it consists of a single clause, e.g.
{:aggregation [:sum [:field-id 100]]}
The following are valid aggregation clauses:
Aggregations are often used in combination with breakouts
, but this is not required. When an aggregation is used without a breakout
, the query will
return a single row with a single value. When one or more breakout
fields is specified, it will return a row for each distinct value.
Suppose we have a table of venues, with a price
column representing the number of $$$
we'd see on a Yelp-like app.
A count
aggregation with no breakout returns the total number of rows, while breaking out by price
returns the count of venues for each given price:
{:aggregation [:count]}
-> [[100]]
{:aggregation [:count], :breakout [<price>]}
-> [[1 22]
[2 59]
[3 13]
[4 6]]
In future iterations of the QL (probably MBQL '98SE
or MBQL ME
), multiple aggregation clauses will also be allowed, but for now, only a single aggregation can be specified.
Older versions of MBQL supported an additional aggregation type, rows
. In MBQL '95, this was made the default behavior, and was ignored by the Query Processor;
in MBQL '98, it is considered deprecated, and the QP will issue a warning when it is encountered.
Return the average value of a numeric field.
- [
:avg
concrete-field
]
Return the count of rows in the source-table
. This takes a single optional arg, a field:
- [
:count
] - [
:count
concrete-field
]
If field is specified, the query retuns the count of rows where field has a non-nil
value.
count
is analogous to SQL's COUNT
. With no args, it behaves like COUNT(*)
; with field,
it is analogous to COUNT(column_name)
.
Returns the count of rows for which filter-clause
returns true.
- [
:count-where
filter-clause
]
Return the cumulative count of a numeric field. This is useful for doing things like total number of sales over time -- charts that go "up and to the right". 📈
- [
:cum-count
concrete-field
]
This aggregation is implemented entirely by middleware on the backend, so individual drivers don't need to worry about handling it. Note that it doesn't make particular sense
to use this aggregation without any breakout columns; in that case, cum-count
will be treated the same as count
Return the cumulative sum of a numeric field.
- [
:cum-sum
concrete-field
]
This aggregation is implemented entirely by middleware on the backend, so individual drivers don't need to worry about handling it. Note that it doesn't make particular sense
to use this aggregation without any breakout columns; in that case, cum-sum
will be treated the same as sum
.
Return the number of distinct values of a field.
- [
:distinct
concrete-field
]
This is analogous to COUNT(DISTINCT column)
in SQL.
Return the standard deviation of values of a numeric field.
- [
:stddev
concrete-field
]
This is not supported by all drivers; drivers that support it declare the feature standard-deviation-aggregations
.
Return the sum of all values of a numeric field. This is analogous to SQL SUM(column)
.
- [
:sum
concrete-field
]
Depending on the database and underlying column type, the results will either by an integer or a floating-point.
Returns the sum of all values of concrete-field
in rows for which filter-clause
returns true.
- [
:count-where
concrete-field
filter-clause
]
Return the minimum value of a numeric or datetime field. This is analogous to SQL MIN(column)
.
- [
:min
concrete-field
]
Return the maximum value of a numeric or datetime field. This is analogous to SQL MAX(column)
.
- [
:min
concrete-field
]
Returns the share of rows for which filter-clause
returns true.
- [
:share
filter-clause
]
- {
:breakout
[&concrete-field
]}
Breakouts group a query by the distinct values of one or more columns. When used in conjunction with an aggregation, they are
analogous to GROUP BY
statements in SQL. Unlike SQL, however, breakout clauses can be used
without aggregate functions; in this case, they return the distinct values of a field, analogous to SQL's SELECT DISTINCT
.
;; Get distinct values of Field 10
;; Equivalent SQL: SELECT DISTINCT field_10
{:breakout [[:field-id 10]]}
;; Count of all rows broken out by (i.e., grouped by) distinct values of Field 10
;; Equivalent SQL: SELECT COUNT(*) GROUP BY field_10
{:aggregation [:count]
:breakout [[:field-id 10]]}
- {
:expressions
{expression-name
expression
}}
Expressions are used to add new columns to the results of a query; for each row, their values are derived from calculations involving the values of other columns and/or numeric constants.
Suppose we have a table called sales
with data like:
subtotal | total |
---|---|
10.00 | 11.00 |
50.00 | 52.50 |
40.00 | 41.00 |
Now suppose we'd like to see what the sales tax for each sale was. We can add an expression to derive sales_tax
from total - subtotal
. The MBQL form for doing so looks like:
{:expressions {:sales_tax [:- [:field-id <id of total>]
[:field-id <id of subtotal>]]}}
The generated SQL will look something like:
SELECT subtotal, total, (total - subtotal) AS sales_tax
FROM sales
The results of a query including this :expressions
clause would look like:
subtotal | total | sales_tax |
---|---|---|
10.00 | 11.00 | 1.00 |
50.00 | 52.50 | 2.50 |
40.00 | 41.00 | 1.00 |
Expressions are not available for all drivers; drivers that offer them advertise the :expressions
feature.
- [
+
arg1concrete field
|number literal
|expression
arg2concrete field
|number literal
|expression
] - [
-
arg1concrete field
|number literal
|expression
arg2concrete field
|number literal
|expression
] - [
/
arg1concrete field
|number literal
|expression
arg2concrete field
|number literal
|expression
] - [
*
arg1concrete field
|number literal
|expression
arg2concrete field
|number literal
|expression
]
The behavior of the various expression operators above should be self-explanatory. Nested expressions may be used as one or both arguments, as may numeric literals; note, however, that field references should refer to a field with numeric values, or the query will fail (it doesn't make sense to generate to try to divide a string, for example). Field references also may not be expression references, which are otherwise allowed wherever a concrete field is specified; this restriction reflects inherent limitations in underlying database systems.
You can refer to the results of expressions in other clauses. See expression references for more details.
More operators may be added in the future if expressions prove popular. Possibilities include string operators, such as concatenation, uppercasing, lowercasing, etc.
- {
:fields
[&field
]}
Conceptually similar to a SQL SELECT
statement; specifies which Fields
the query should return. When specified, fields
is a sequence of one or
more field references:
{:fields [[:field-id 100] [:field-id 200]]}
- {
:filter
filter-clause
}
filter
is used to "filter" the the rows returned by a query, and is analogous to the SQL WHERE
clause.
A filter clause is one of the following:
and
or
not
=
!=
<
>
<=
>=
is-null
not-null
between
inside
starts-with
contains
does-not-contain
ends-with
time-interval
- [
:and
& clausesfilter-clause
]
Compound filter clause: return rows that satisfy all clauses. clauses can be any valid filter clause,
including nested compound :and
or :or
clauses.
If only a single clause is passed, it is treated as if there were no surrounding :and
clause:
[:and [:= <field> <value>]] -> [:= <field> <value>]
- [
:and
& clausesfilter-clause
]
Compound filter clause: return rows that satisfy one or more clauses. clauses can be any valid filter clause,
including nested compound :and
or :or
clauses.
If only a single clause is passed, it is treated as if there were no surrounding :or
clause:
[:or [:= <field> <value>]] -> [:= <field> <value>]
- [
:not
filter-clause
]
The not
filter returns results that do not match its argument (i.e., it logically negates its argument). not
works exactly like SQL's NOT
or Clojure's not
function.
In most cases a not
form is automatically translated to a simpler, logically equivalent form:
(not (and <x> <y>)) -> (or (not <x>) (not <y>))
(not (not <x>)) -> <x>
(not (= <x> <y>) -> (!= <x> <y>)
The negation of some filters (like starts-with
) have no logical equivalent in MBQL, so drivers still need to know how to handle not
.
- [
:=
concrete-field
value
&value
]
With a single value
, return rows where the values of field match value. With multiple values, this behaves like a
SQL IN
operator, and returns rows that match any of the values.
[:= <field> 100] ; return rows where <field> == 100
[:= <field> 100 200] ; return rows where <field> == 100 *or* field == 200
Internally, =
filters with multiple values are translated to compound statements, e.g.:
[:= <field> 100 200]
-> [:or [:= <field> 100]
[:= <field> 200]]
- [
:!=
concrete-field
value
&value
]
With a single value
, return rows where the values of field are not equal to value. With multiple values, this behaves like a
SQL NOT IN
operator, and returns rows that match none of the values.
[:!= <field> 100] ; return rows where <field> != 100
[:!= <field> 100 200] ; return rows where <field> != 100 *and* field != 200
Internally, !=
filters with multiple values are translated to compound statements, e.g.:
[:!= <field> 100 200]
-> [:and [:!= <field> 100]
[:!= <field> 200]]
- [
:<
fieldconcrete-field
valueorderable-value
]
Return results where field is less than value. field and value must be orderable, i.e. numbers or a datetimes.
- [
:>
fieldconcrete-field
valueorderable-value
]
Return results where field is greater than value. field and value must be orderable, i.e. numbers or a datetimes.
- [
:<=
fieldconcrete-field
valueorderable-value
]
Return results where field is less than or equal to value. field and value must be orderable, i.e. numbers or a datetimes.
- [
:>=
fieldconcrete-field
valueorderable-value
]
Return results where field is greater than or equal to value. field and value must be orderable, i.e. numbers or a datetimes.
- [
:is-null
fieldconcrete-field
]
Return results where field is nil
. Convenience for [:= <field> nil]
. This filter isn't particularly useful in my opinion and may be deprecated in the future; prefer using =
instead.
- [
:not-null
fieldconcrete-field
]
Return results where field is non-nil
. Convenience for [:!= <field> nil]
. This filter isn't particularly useful in my opinion and may be deprecated in the future; prefer using !=
instead.
- [
:between
fieldconcrete-field
minorderable-value
maxorderable-value
]
Analogous to the SQL BETWEEN
operator.
Return results where field is between min and max, inclusive. field, min, and max must be orderable
, i.e. numbers
or datetimes.
between
is conceptually similar to
[:and [:>= <field> <min>]
[:<= <field> <max>]]
and can be implemented by drivers with no corresponding native concept as such.
inside
is used for doing geo bounding boxes:
- [
:inside
latconcrete-field
lonconcrete-field
lat-maxnumeric-literal
lon-minnumeric-literal
lat-minnumeric-literal
lon-maxnumeric-literal
]
Drivers don't need to specifically handle inside
filters. Internally, they're automatically translated to to a pair of between
clauses:
[:inside <lat> <lon> <lat-max> <lon-min> <lat-min> <lon-max>]
-> [:and [:between <lat-field> <lat-min> <lat-max>]
[:between <lon-field> <lon-min> <lon-max>]]
- [
:starts-with
fieldconcrete-field
valuestring-literal
]
The starts-with filter restricts results to those where values of string field start with the substring value. Analogous to SQL <field> LIKE '<value>%'
.
- [
:contains
fieldconcrete-field
valuestring-literal
]
The contains filter restricts results to those where values of string field contain the substring value. Analogous to SQL <field> LIKE '%<value>%'
.
e.g.
;; return results where values of string Field 10 contain the substring "BBQ"
{:filter [:contains [:field-id 10] "BBQ"]}
- [
:does-not-contain
fieldconcrete-field
valuestring-literal
]
The does not contain filter restricts results to those where values of string field do not contain the substring value. Analogous to SQL NOT (<field> LIKE '%<value>%')
.
This filter is just syntactic sugar for wrapping a contains
filter in a not
form, and is implemented as such on the backend (i.e., individual drivers don't need to worry about handling this clause directly).
[:does-not-contain <field> <string>] -> [:not [:contains <field> <string>]]
Prefer using the equivalent not
/contains
form instead whenever possible; this form will likely be deprecated at some point in the future. It is provided for the time being solely as a convenience to the Metabase frontend until support for not
is implemented.
- [
:ends-with
fieldconcrete-field
valuestring-literal
]
The ends-with filter restricts results to those where values of string field end with the substring value. Analogous to SQL <field> LIKE '%<value>'
.
- [
:time-interval
fieldconcrete-field
n:current
|:last
|:next
|integer-literal
unitrelative-datetime-unit
]
time-interval
is syntactic sugar for restricting results to ones where datetime field matches a certain datetime or range of datetimes.
;; Assuming today is Feb 8th, 2016...
;; return results where <field> is any time on Feb 8th 2016
[:time-interval <field> :current :day]
;; return results where <field> is during the previous month (any date in Jan 2016)
[:time-interval <field> :last :month]
;; Return results in the last 30 days, excluding the current day (Jan 8th <-> Feb 7th)
[:time-interval <field> -30 :day]
:current
, :last
, and :next
are allowed as values on n for readability purposes and have the same effect as as the integers 0
, -1
, and 1
, respectively.
time-interval
is translated into a =
or between
filter, depending on the value of n.
TODO Examples of translation to =
/between
clauses
- {
:limit
ninteger-literal
}
limit
specifies the maximum number of rows that should be returned by the query. It is analogous to a SQL LIMIT
clause (or SELECT TOP
in MS SQL).
ex.
{:source-table 20
:limit 10} ; return the first 10 rows of Table 20
n must be greater than zero.
- {
:order-by
[&order-by-clause
]}
You can specify how results should be sorted with order-by
. When specified, it consists of one or more order by clauses, each of which specify a field
and sort direction (ascending or descending).
order-by
is analogous to SQL's ORDER BY
. Like SQL, you can specify multiple columns to sort by; sorting is done by the first column,
then by the second in the case of duplicate values for the first, and so forth.
Ex.
;; Sort by values of Field 10 in ascending order
{:order-by [[:asc [:field-id 10]]]}
;; Sort by :count in descending order
{:aggregation [:count]
:breakout [[:field-id 10]]
:order-by [[:desc [:aggregate-field 0]]]}
- [direction
:asc
|:desc
fieldfield
]
- {
:source-table
integer-literal
}
The source table clause specifies the ID of the Metabase Table that should be queried. A Metabase Table is the internal object used to represent a physical table/collection/datasource/etc and store metadata about it.
This clause is roughly equivalent in purpose to a simple SQL FROM
clause (i.e., on with no joins or sub-selects).
Local Field References are references to Metabase Fields that belong to this Table. To include data from other Tables (and perform the equivalent of a SQL JOIN
) you
can include Foreign Field References somewhere in your query.
- [
:named
aggregation-clause
] - {
:source-query
query
} :binning-strategy
:field-literal
- joins +
:joined-field
- Backend
- Metabase Developer Reference
- Product Management
- QA and Testing
- Writing A Driver
- Driver Notices
- REST API Notices
- Writing style guide for documentation and blog posts (WIP)