Jinja can be used in combination with SQL to create dynamic and flexible SQL queries. Jinja allows you to include variables and expressions in your SQL queries, and to use control structures like if / else and for loops to control the flow of execution and generate more complex queries.
Reuse is valuable because it promotes consistency in your data pipelines, saving time and improving maintainability: maintaining 1 configurable query is easier than maintaining 10 "very similar yet slightly different" queries.
Jinja enables you to generate SQL queries dynamically based on input data, as in the following example:
{% set columns = [ 'first_name', 'last_name', 'username', 'email' ] %}
SELECT
{%- for value in columns %}
{{ value }}
{%- if not loop.last -%},{% endif -%}
{% endfor %}
FROM users;
rendering the above template outputs
SELECT
first_name,
last_name,
username,
email
FROM users;
Declaring and using columns instead of having to write each value in the query makes the query more readable. This query template can be even more generic, making the table name configurable as well
{% set columns = [ 'first_name', 'last_name', 'username', 'email' ] %}
{% set table_name = "users" %}
SELECT
{%- for value in columns %}
{{ value }}
{%- if not loop.last -%}, {% endif -%}
{% endfor %}
FROM {{ table_name }}
This template now works for any basic query!
You can keep going and add support for a where clause, when provided
{% set columns = [ 'last_name', 'username', 'email' ] %}
{% set table_name = "users" %}
{% set clauses = {"first_name": "John", "age": 25} %}
SELECT
{%- for value in columns %}
{{ value }}
{%- if not loop.last -%}, {% endif -%}
{% endfor %}
FROM {{ table_name }}
{% if clauses %}
WHERE
{% for name, value in clauses.items() -%}
{{ name -}} = {%- if value is string -%}"{%- endif -%}{{- value }}{%- if value is string -%}"{%- endif -%}
{% if not loop.last %} AND {% endif -%}
{% endfor %}
{% endif %}
Rendering the above results in
SELECT
last_name,
username,
email
FROM users
WHERE
first_name="John" AND age=25
There's a lot going on in the last part of the query, let's break it down:
clauses have been defined: according to truthiness rules for dictionaries, this condition will only be True if the dictionary contains at least one itemWHERE to the queryclauses and for each of themname clause to the query followed by an equal sign (=), thenvalue is of type string, surround it with quotesvalue to the queryANDThis query is still not bullet-proof (it cannot deal with IN clauses, for example), but it can already get you pretty far.
You can do even more by using macros and/or template inheritance to reuse common template code, simplifying your ETL pipelines.
In PushMetrics SQL blocks you can preview your evaluated Jinja by clicking the Jinja button:

Sign up and start using PushMetrics for free.
Or schedule a demo and discuss your use case.