Dynamic SQL Query Formation with Jinja Template

Constructing dynamic SQL queries is often a necessity. These queries adapt to varying conditions, allowing for flexible interactions with databases. Python, being a versatile language, provides several tools for dynamic SQL generation. Among these, Jinja templates stand out for their simplicity and effectiveness.

Rajan Sahu
4 min readMay 8, 2024

What is the Jinja Template?

Jinja is a powerful templating engine for Python. It enables the creation of dynamic content, including SQL queries, by embedding variables, expressions, and control structures directly into the template. Jinja templates facilitate the separation of logic and presentation, enhancing code readability and maintainability.

Why Jinja Template for Constructing Dynamic SQL Queries?

The need for dynamic SQL arises when the structure of a query must adapt based on runtime conditions. Jinja templates excel in this scenario due to their ability to incorporate variables, conditional statements, and loops directly into the query template. This flexibility empowers developers to construct SQL queries dynamically, catering to diverse requirements.

Advantages of Jinja Template:

  1. Simplicity: Jinja templates utilize a straightforward syntax, making them accessible to developers of all levels.
  2. Flexibility: Variables, conditional statements, and loops can be seamlessly integrated into SQL query templates, allowing for dynamic query construction.
  3. Readability: By separating logic from presentation, Jinja templates enhance the readability and maintainability of SQL query code.
  4. Ease of Use: Jinja integrates seamlessly with Python, offering a familiar environment for developers to work with.

Disadvantages of Jinja Template:

  1. Security Risks: Jinja templates may be susceptible to injection attacks if not handled properly. Care must be taken to sanitize input data to prevent security vulnerabilities.
  2. Performance Overhead: While Jinja templates provide flexibility, excessive use of dynamic SQL queries may introduce performance overhead, impacting application efficiency.
  3. Learning Curve: Although Jinja templates boast simplicity, mastering advanced features and best practices may require some learning investment.

Examples of Jinja Template Usage:

1. Using Variables in SQL Query:

from jinja2 import Template

query_str = "SELECT * FROM {{table_name}}"
template = Template(query_str)
query = template.render(table_name="users")

Output: "SELECT * FROM users"

2. Multiple Variables in SQL Query:

from jinja2 import Template

query_str = "SELECT * FROM orders WHERE product = '{{ product }}' AND quantity >= {{ min_quantity }}"
template = Template(query_str)
query = template.render(product='Laptop', min_quantity=5)

Output: "SELECT * FROM orders WHERE product = 'Laptop' AND quantity >= 5"

3. Using Conditional If Statements in SQL Query:

from jinja2 import Template
query_str = """SELECT * FROM users {% if user_age >= 18 %}WHERE age >= {{ user_age }}{% endif %};"""
template = Template(query_str)
query = template.render(user_age=30)

Output: "SELECT * FROM users WHERE age >= 30;"

4. Using If-Else Statements in SQL Query:

from jinja2 import Template

query_str = """SELECT * FROM users WHERE{% if user_age >= 18 %} adult >= True {% else %} adult = False {% endif %};"""
template = Template(query_str)
query = template.render(user_age=30)

Output: "SELECT * FROM users WHERE adult >= True;"

5. Using If-Elif-Else Statements in SQL Query:

from jinja2 import Template

query_str = """SELECT * FROM products where
{% if product_stock >= 1000 %} performance = 'bad'
{% elif product_stock >= 300 and product_stock < 1000 %} performance = 'average'
{% else %} performance = 'good'
{% endif %}
"""
template = Template(query_str)
query = template.render(product_stock=999)

Output: "SELECT * FROM products WHERE performance = 'average'"

6. Nested If Statements in SQL Query:

from jinja2 import Template

query_str = """SELECT *
FROM products where
{% if product_category == "Electronics" %}
product_category = '{{product_category}}'
{% if product_price > 500 %}
product_type = 'expensive'
{% else %}
product_type = 'normal'
{% endif %}
{% else %}
product_category = 'Others'
{% endif %}
"""
template = Template(query_str)
query = template.render(product_category="Electronics", product_price=450)

Output: "SELECT * FROM products WHERE product_category = 'Electronics' AND product_type = 'normal'"

7. Using For Loop in SQL Query:

from jinja2 import Template
query_str = """SELECT *
FROM orders
WHERE order_id IN (
{% for order_id in order_ids %}
{{ order_id }},
{% endfor %}
)
"""

template = Template(query_str)
query = template.render(order_ids=[1234, 5678, 9012])

Output: "SELECT * FROM orders WHERE order_id IN (1234, 5678, 9012,)"

8. Using nested for loop

from jinja2 import Template

query_str = """SELECT *
FROM orders
WHERE order_id IN (
{% for project_id in project_ids %}
{% for order_id in orders[project_id] %}
{{ order_id }},
{% endfor %}
{% endfor %}
)
"""

template = Template(query_str)
orders = {
'project1': [1234, 5678],
'project2': [9012, 3456],
'project3': [7890]
}
query = template.render(project_ids=orders.keys(), orders=orders)

Output: SELECT * FROM orders WHERE order_id IN ( 1234, 5678, 9012, 3456, 7890,)

9. Built-in Filter of Jinja templates

from jinja2 import Template

query_str = """SELECT *
FROM users
WHERE username = '{{ username | lower }}'"""

template = Template(query_str)
query = template.render(username='JOHN')

Output: SELECT * FROM users WHERE username = ‘john’

Important:

We plan to publish a follow-up article in which we will go over how to add a custom filter to a Jinja template. The content of this article will rely on your feedback, so please let us know if you would like to see the second part.

Conclusion

Jinja templates offer a robust solution for constructing dynamic SQL queries in Python. With its simplicity, flexibility, and readability, Jinja simplifies the process of generating SQL queries tailored to specific requirements. However, developers must remain vigilant regarding security risks and performance considerations when utilizing Jinja templates in their applications.

Reference:

Thank you for reading. If you find something wrong or better ways to do it, let me know in the comments below.

If you like the post, hit the 👏 button below so that others may find it useful. You can follow me on GitHub and connect with me on Linkedin.

--

--

Rajan Sahu

Backend and Data Engineer by Day; Teacher, Friend and Content-Writer by night.