Odoo SQL Join Queries

Exploring the basics, Providing practical examples, and Offering tips for optimization.

Introduction:

As an Odoo developer, understanding how to effectively write SQL queries can greatly enhance your ability to work with the database and retrieve data efficiently. In this blog post, we will dive into the world of SQL queries in Odoo, exploring the basics, providing practical examples, and offering tips for optimization.


1. The Power of SQL Queries in Odoo:

SQL (Structured Query Language) is a powerful tool for interacting with databases, and Odoo provides the flexibility to utilize SQL queries when necessary. Whether you need to retrieve complex data, perform calculations, or join multiple tables, SQL queries can be a valuable asset.


2. Writing SQL Queries in Odoo:

To write SQL queries in Odoo, you can leverage the ORM (Object Relational Mapping) framework, which allows you to work with databases using Python classes and methods. Let's explore an example:


python

def get_product_sales_amount(self): query = ''' SELECT pp.name AS product_name, SUM(so.amount_total) AS total_sales_amount FROM product_product AS pp JOIN sale_order_line AS sol ON sol.product_id = pp.id JOIN sale_order AS so ON so.id = sol.order_id GROUP BY pp.name ''' self.env.cr.execute(query) result = self.env.cr.fetchall() return result

In the above example, we retrieve the total sales amount for each product by joining the product_product, sale_order_line, and sale_order tables. The GROUP BY clause groups the results by product name, providing a concise overview.

Understanding different types of SQL joins is essential for working with complex data structures in Odoo.

Inner Join:

The inner join is the most common type of join, combining records from two tables based on a matching condition. Let's consider an example:


python

def get_matching_customers(self): query = ''' SELECT c.name AS customer_name, o.order_date FROM customer AS c INNER JOIN orders AS o ON c.id = o.customer_id ''' self.env.cr.execute(query) result = self.env.cr.fetchall() return result

In the above example, we retrieve the customer name and order date by performing an inner join between the customer and orders tables based on the matching customer_id field.


Left Join:

A left join retrieves all records from the left table and the matching records from the right table. If no match is found, NULL values are returned for the right table. Here's an example:


python

def get_all_customers_with_orders(self): query = ''' SELECT c.name AS customer_name, o.order_date FROM customer AS c LEFT JOIN orders AS o ON c.id = o.customer_id ''' self.env.cr.execute(query) result = self.env.cr.fetchall() return result

In the above example, we retrieve all customers and their respective order dates. If a customer has no orders, the order date is returned as NULL.


Right Join:

A right join is similar to a left join but retrieves all records from the right table and the matching records from the left table. If no match is found, NULL values are returned for the left table. Consider this example:


python

def get_all_orders_with_customers(self): query = ''' SELECT c.name AS customer_name, o.order_date FROM customer AS c RIGHT JOIN orders AS o ON c.id = o.customer_id ''' self.env.cr.execute(query) result = self.env.cr.fetchall() return result

In the above example, we retrieve all orders and their respective customer names. If an order has no customer associated with it, the customer name is returned as NULL.


Full Outer Join:

A full outer join combines the results of both the left and right tables, including all records from both sides. If no match is found, NULL values are returned. Here's an example:


python

def get_all_customers_and_orders(self): query = ''' SELECT c.name AS customer_name, o.order_date FROM customer AS c FULL OUTER JOIN orders AS o ON c.id = o.customer_id ''' self.env.cr.execute(query) result = self.env.cr.fetchall() return result

In the above example, we retrieve all customers and their respective order dates, including unmatched records from both tables.


3. Tips for Optimizing SQL Queries:

When working with SQL queries in Odoo, optimizing their performance is crucial. Here are a few tips to enhance query efficiency:

  • Use appropriate indexes to speed up data retrieval.
  • Minimize the use of wildcard characters in the WHERE clause for faster filtering.
  • Avoid unnecessary joins by carefully selecting only the required tables.
  • Utilize database-specific optimizations if applicable.


4. Security Considerations:

While SQL queries offer great flexibility, it's important to handle security effectively. Odoo provides mechanisms to prevent SQL injection vulnerabilities, such as parameter binding and escaping user input.


Odoo Reports and Analysis: Unleashing the Power of SQL Join Queries

Odoo, the popular open-source ERP system, offers comprehensive features for managing business operations. One powerful aspect of Odoo is its reporting capabilities, which allow users to generate custom reports, perform data analysis, and create insightful pivot, graph, etc tables. In this blog post, we will explore how to leverage SQL join queries within Odoo to unlock advanced reporting and analysis features. Let's dive in!


Odoo QWEB Reports:

Let's assume we have a model: SaleOrder.

1. Define the Model:

python

from odoo import models, fields class SaleOrder(models.Model): _name = 'sale.order' name = fields.Char(string='Order Number') order_date = fields.Date(string='Order Date') def get_comprehensive_report(self): query = """ SELECT so.name, so.order_date, sol.product_id, sol.quantity, sol.price FROM sale_order so JOIN sale_order_line sol ON so.id = sol.order_id """ self._cr.execute(query) results = self._cr.fetchall() return results

2. Create a Report:

xml

<odoo> <data> <report id="report_sale_order" model="sale.order" string="Sale Order Report" name="module_name.report_sale_order" report_type="qweb-pdf" file="module_name.report_sale_order" attachment_use="True" /> <template id="report_sale_order"> <t t-call="web.html_container"> <t t-foreach="docs" t-as="result"> <div class="page"> <h2>Sale Order: <t t-esc="result[0]"/></h2> <table class="table table-condensed"> <thead> <tr> <th>Product</th> <th>Quantity</th> <th>Price</th> </tr> </thead> <tbody> <tr t-foreach="result[2]" t-as="line"> <td><t t-esc="line[1]"/></td> <td><t t-esc="line[3]"/></td> <td><t t-esc="line[4]"/></td> </tr> </tbody> </table> </div> </t> </t> </template> </data> </odoo>

3. Create the Report Function:

python

from odoo import api, models class SaleOrder(models.Model): _inherit = 'sale.order' @api.multi def print_report(self): report_data = self.get_comprehensive_report() return { 'type': 'ir.actions.report', 'report_name': 'module_name.report_sale_order', 'report_type': 'qweb-pdf', 'data': { 'docs': report_data, }, }

In this example, we have added a get_comprehensive_report method to the SaleOrder model. Inside this method, we execute a custom SQL query that joins the sale_order and sale_order_line tables based on the foreign-key relationship. The results are fetched using self._cr.fetchall().

The report template is similar to the previous example, but instead of using the order and line variables, we directly access the fields from the query results (result[0], result[2], etc.).

The print_report method is updated to fetch the report data using get_comprehensive_report and pass it to the report template.

Remember to replace 'module_name' with your actual module name in the code.

Please note that using raw SQL queries should be done carefully to ensure data security and compatibility with Odoo's ORM features.


Odoo PIVOT Reports:

In Odoo, a pivot report view is a way to present data in a tabular format with rows and columns that can be summarized or aggregated based on specific fields. It allows you to perform multidimensional analysis and provides a visual representation of data that helps in decision-making and data exploration.

Here are some key definitions related to pivot report views in Odoo:

  1. Pivot Report: A pivot report is a type of view in Odoo that displays summarized data in a tabular format. It allows you to define rows, columns, and measures to group and aggregate data.

  2. Rows: Rows in a pivot report represent a field or set of fields that define the rows of the report. Each unique combination of values in the row fields creates a distinct row in the pivot report.

  3. Columns: Columns in a pivot report represent a field or set of fields that define the columns of the report. Each unique combination of values in the column fields creates a distinct column in the pivot report.

  4. Measures: Measures in a pivot report are the fields that hold the summarized or aggregated data. These fields are typically numeric and can be summed, averaged, counted, or subjected to other aggregation functions.

  5. Summarization: Summarization refers to the process of applying aggregation functions to the measure fields in a pivot report. Aggregation functions like sum, average, count, min, max, etc., are used to calculate summary values based on the data.

  6. Data Exploration: Pivot report views provide an interactive way to explore data by allowing users to drill down, expand or collapse rows and columns, apply filters, and change the structure of the report dynamically.


Python code to generate a pivot report in Odoo:

Example : 

pythonCopy codefrom odoo import models, fields

class SaleOrderAnalysisPivot(models.Model):
    _name = 'sale.order.analysis.pivot'
    _description = 'Sale Order Analysis Pivot'
    _auto = False

    product_id = fields.Many2one('product.product', string='Product')
    order_date = fields.Date(string='Order Date')
    total_quantity = fields.Float(string='Total Quantity')
    total_price = fields.Float(string='Total Price')
    customer_id = fields.Many2one('res.partner', string='Customer')
    salesperson_id = fields.Many2one('res.users', string='Salesperson', compute='_compute_salesperson_id', store=True)
    shipping_method = fields.Selection([
        ('express', 'Express'),
        ('standard', 'Standard')
    ], string='Shipping Method')

    def _compute_salesperson_id(self):
        for record in self:
            order = self.env['sale.order'].search([('product_id', '=', record.product_id.id)], limit=1)
            record.salesperson_id = order.salesperson_id.id if order else False

    def init(self):
        self._cr.execute("""
            CREATE OR REPLACE VIEW sale_order_analysis_pivot AS (
                SELECT
                    so.product_id,
                    so.order_date,
                    SUM(so.quantity) AS total_quantity,
                    SUM(so.price) AS total_price,
                    so.customer_id,
                    so.salesperson_id,
                    so.shipping_method
                FROM
                    sale_order so
                JOIN
                    product_product p ON so.product_id = p.id
                LEFT JOIN
                    res_users u ON so.salesperson_id = u.id
                RIGHT JOIN
                    res_partner partner ON so.customer_id = partner.id
                GROUP BY
                    so.product_id,
                    so.order_date,
                    so.customer_id,
                    so.salesperson_id,
                    so.shipping_method
            )
        """)

class SaleOrder(models.Model):
    _inherit = 'sale.order'

    analysis_pivot_ids = fields.One2many('sale.order.analysis.pivot', 'product_id', string='Analysis Pivot')

In this example, we create the SaleOrderAnalysisPivot model that represents the pivot report view. It includes the previously defined fields (product_id, order_date, total_quantity, total_price) and introduces additional fields for the join operations (customer_id, salesperson_id, shipping_method).

The _compute_salesperson_id method is added to compute the salesperson_id field value based on the related salesperson of the order. It uses a search query to find the order with the matching product ID and retrieves the associated salesperson.

The init method is modified to execute a SQL query that creates the pivot report view sale_order_analysis_pivot. It includes join operations using JOIN, LEFT JOIN, and RIGHT JOIN keywords to perform inner join, left join, and right join respectively. The GROUP BY clause groups the data based on the specified fields.

The SaleOrder model is updated with the analysis_pivot_ids field to display the pivot report in the sale.order form or tree view.

Remember to import the necessary modules in your Python file (from Odoo import models, fields) and replace 'sale.order' with the actual model name and 'product.product', 'res.partner', and 'res.users' with the correct model names for your product, customer, and salesperson records.

Conclusion:

SQL queries are a powerful tool in Odoo for retrieving and manipulating data in the database. By mastering SQL queries, you can unlock advanced capabilities, optimize performance, and efficiently work with complex data structures.

We hope this blog post has provided you with a solid understanding of SQL queries in Odoo and offered practical examples to guide you along the way. Start harnessing the power of SQL queries in your Odoo projects and elevate your development skills to the next level.


Odoo SQL Join Queries
BizzAppDev Expert May 26, 2023
Share this post
Sign in to leave a comment
Achieving Code Coverage With Automated Test Cases in Odoo
Use built-in testing framework that comes with Odoo