Skip to content
Snippets Groups Projects
13-sql-parameters.md 8.52 KiB
Newer Older
Maz Ameli's avatar
Maz Ameli committed
## SQL Parameters
Maz Ameli's avatar
Maz Ameli committed

Maz Ameli's avatar
Maz Ameli committed
Metabase has the flexible ability to allow variables in native (SQL) queries. This lets you dynamically replace values in your queries using filter widgets or through the query's URL.

![Variables](images/sql-parameters/02-widget.png)

Options and settings for your variables will appear in the `Variables` side panel of the native query builder once you've defined a variable. So, how do you define a variable?

![Variables](images/sql-parameters/01-variables.png)

### Defining Variables
Maz Ameli's avatar
Maz Ameli committed

Typing `{% raw %}{{variable_name}}{% endraw %}` in your native query creates a variable called `variable_name`. Variables can be given types in the side panel, which changes their behavior. All variable types other than "Field Filter" will cause a filter widget to be placed on this question corresponding to the chosen variable type. When a value is selected via a filter widget, that value replaces the corresponding variable in the SQL template, wherever it appears. If you have multiple filter widgets, you can click and drag on any of them to move and reorder them.
Maz Ameli's avatar
Maz Ameli committed

This example defines a variable called `cat`, allowing you to dynamically change the `WHERE` clause in this query:
Maz Ameli's avatar
Maz Ameli committed
```
SELECT count(*)
FROM products
Sameer Al-Sakran's avatar
Sameer Al-Sakran committed
WHERE category = {% raw %}{{cat}}{% endraw %}
Maz Ameli's avatar
Maz Ameli committed
```

If you're writing a native MongoDB query, your query would look more like this, with the `cat` variable being defined inside of the `match` clause.
Maz Ameli's avatar
Maz Ameli committed

{% raw %}[{ $match: { category: {{cat}} } }]{% endraw %}
```

### The Field Filter variable type

Setting a variable to the "Field Filter" type allows you to map it to a field in any table in the current database, and lets you display a dropdown filter widget filled with the values of the field you connected it to. Field filter variables also allow you to connect your SQL question to a dashboard filter if you put it in a dashboard.
A field filter variable inserts SQL similar to that generated by the GUI query builder when adding filters on existing columns. This is useful because it lets you do things like insert dynamic date range filters into your native query. When adding a field filter, you should link that variable to a specific column. Field filter variables should be used inside of a `WHERE` clause in SQL, or a `$match` clause in MongoDB.
Maz Ameli's avatar
Maz Ameli committed

**Note:**
- Table aliases are not supported. This is because field filters generate SQL based on the mapped field.
- Some databases require the schema in the `FROM` clause. An example for Oracle would be `FROM "schema"."table"`. In BigQuery, back ticks are needed, like `` FROM `dataset_name.table` ``.
Maz Ameli's avatar
Maz Ameli committed
Example:
Maz Ameli's avatar
Maz Ameli committed
```
SELECT count(*)
FROM products
WHERE {% raw %}{{date_var}}{% endraw %}
```

A MongoDB native query example might look like this:

```
{% raw %}[ {$match: {{date_var}} } ]{% endraw %}
Maz Ameli's avatar
Maz Ameli committed
```

#### Creating SQL question filters using field filter variables
Maz Ameli's avatar
Maz Ameli committed

First, insert a variable tag in your SQL, like `{% raw %}{{my_var}}{% endraw %}`. Then, in the side panel, select the "Field Filter" variable type, and choose which field to map your variable to. In order to display a filter widget, you'll have to choose a field whose "Type" in the "Data Model" section of the Admin Panel is one of the following:
Maz Ameli's avatar
Maz Ameli committed

- Category
- City
- Entity Key
- Entity Name
- Foreign Key
- State
- UNIX Timestamp (Seconds)
- UNIX Timestamp (Milliseconds)
- ZIP or Postal Code
The field can also be a datetime, which can be left as "No special type" in the data model.
You'll then see a dropdown labeled "Widget," which will let you choose the kind of filter widget you want on your question, which is especially useful for datetime fields. You can select "None" if you don't want a widget on the question at all, which you might do, for example, if you just want to allow this question to be mapped to a dashboard filter (see more on that below).
**Note:** If you're not seeing the option to display a filter widget, make sure the mapped field is set to one of the above types, and then try manually syncing your database from the "Databases" section of the Admin Panel to force Metabase to scan and cache the field's values.

Filter widgets **can't** be displayed if the variable is mapped to a field marked as:
Maz Ameli's avatar
Maz Ameli committed

- Avatar Image URL
- Description
- Email
- Enum
- Field containing JSON
- Image URL
- Number
- Latitude
- Longitude
- URL

#### Setting a default value
Maz Ameli's avatar
Maz Ameli committed

If you input a default value for your field filter, this value will be selected in the filter whenever you come back to this question. If you clear out the filter, though, no value will be passed (i.e., not even the default value). **The default value has no effect on the behavior of your SQL question when viewed in a dashboard.**
##### Default value in the query
You can also define default values directly in your query, which are useful when defining complex default values. Note that the hash (`#`) might need to be replaced by the comment syntax of the database you're using. Some databases use double-dashes (`--`) as comment syntax.

Current example for a Date filter:
Maz Ameli's avatar
Maz Ameli committed

```
SELECT p.*
FROM products p
WHERE p.createdAt = [[ {% raw %}{{dateOfCreation}}{% endraw %} #]]CURRENT_DATE()
#### Connecting a SQL question to a dashboard filter
In order for a saved SQL/native question to be usable with a dashboard filter, it must contain at least one field filter. The kind of dashboard filter that can be used with the SQL question depends on the field that you map to the question's field filter(s). For example, if you have a field filter called `{% raw %}{{var}}{% endraw %}` and you map it to a State field, you can map a Location dashboard filter to your SQL question. In this example, you'd create a new dashboard or go to an existing one, click the "Edit" button, add the SQL question that contains your State field filter, add a new dashboard filter or edit an existing Location filter, then click the dropdown on the SQL question card to see the State field filter. [Learn more about dashboard filters here](08-dashboard-filters.md).

![Field filter](images/sql-parameters/state-field-filter.png)
Maz Ameli's avatar
Maz Ameli committed
### Optional Clauses
To make a clause optional in your native query, type `[[brackets around a {% raw %}{{variable}}{% endraw %}]]`. If `variable` is given a value, then the entire clause is placed into the template. If not, then the entire clause is ignored.
Maz Ameli's avatar
Maz Ameli committed

In this example, if no value is given to `cat` from its filter widget or URL, then the query will just select all the rows from the `products` table. But if `cat` does have a value, like `Widget`, then the query will only grab the products with a category type of `Widget`:
Maz Ameli's avatar
Maz Ameli committed
```
SELECT count(*)
FROM products
Sameer Al-Sakran's avatar
Sameer Al-Sakran committed
[[WHERE category = {% raw %}{{cat}}{% endraw %}]]
Maz Ameli's avatar
Maz Ameli committed
```

Or in MongoDB:

```
{% raw %}
[
    [[{
        $match: {category: {{cat}}}
    },]]
    {
        $count: "Total"
    }
]
{% endraw %}
Maz Ameli's avatar
Maz Ameli committed
To use multiple optional clauses you must include at least one regular `WHERE` clause followed by optional clauses, each starting with `AND`.

Example:
Maz Ameli's avatar
Maz Ameli committed
```
SELECT count(*)
FROM products
Sameer Al-Sakran's avatar
Sameer Al-Sakran committed
  [[AND id = {% raw %}{{id}}{% endraw %}]]
  [[AND category = {% raw %}{{category}}{% endraw %}]]
Maz Ameli's avatar
Maz Ameli committed
```

When using a field filter, the column name should not be included in the SQL. Instead, the variable should be mapped to a field in the side panel.

Example:

```
SELECT count(*)
FROM products
WHERE True
  [[AND {% raw %}{{id}}{% endraw %}]]
  [[AND {% raw %}{{category}}{% endraw %}]]
```

### Using an existing question as a sub-query

You can use an existing question in a new query with the following variable syntax:

```
SELECT count(*)
FROM {% raw %}{{#123}}{% endraw %}
```

This will return the number of records returned by the existing question with ID 123. A question's ID is the number at the end of the URL in your browser's location bar, after `/question/`, when viewing the question.

Alternatively, you can select the target question in the sidebar, in the "Question #..." box that appears after typing `{% raw %}{{#}}{% endraw %}` in the query editor. The saved question you select has to be one that's based on the same database as the one you've currently selected in the native query editor.

The same syntax can be used in Common Table Expressions (CTEs), with databases that support them:

```
WITH filtered_products AS {% raw %}{{#123}}{% endraw %}
SELECT count(*)
FROM filtered_products
```

The `{% raw %}{{#123}}{% endraw %}` tag is substituted for the SQL query of the referenced question, surrounded by parentheses.

**Note:** Sub-queries are only supported in SQL databases.

Maz Ameli's avatar
Maz Ameli committed
---

Maz Ameli's avatar
Maz Ameli committed
## Next: automated x-ray explorations
Maz Ameli's avatar
Maz Ameli committed
Learn about how to easily and quickly see automatic explorations of your data with Metabase's powerful [x-ray feature](14-x-rays.md).