Coginiti menu Coginiti menu

Using a Common Table Expression (CTE)

A Common Table Expression (CTE) in SQL is a temporary-named result set you can reference within a SELECT, INSERT, UPDATE, or DELETE statement. It is similar to a subquery, but instead of being embedded in the query, the CTE is defined before the query and can be referenced one or more times within the same query.

The WITH clause defines the CTE and specifies the name, while the SELECT statement defines the result set.

CTEs can simplify complex queries by breaking them into smaller, more manageable parts. This improves readability and maintainability of your query while also allowing you to reuse the CTE identifier set multiple times without repeating the underlying SQL logic.

To write a Common Table Expression (CTE) in SQL, follow these steps:

  1. Initialize the CTE
    Start with the WITH keyword to indicate that you are beginning a CTE.
  2. Name the CTE
    Directly after WITH, provide a meaningful name for the CTE. This name will be used to refer to the CTE later in your SQL query.
  3. Define the CTE’s Query
    Use the AS keyword followed by an open parenthesis (. Inside the parentheses, write the SQL query that constructs the content of the CTE. This query can include any valid SQL such as JOIN operations and WHERE clauses.
  4. Multiple CTEs?
    If you have more than one CTE, separate each with a comma. Only the first CTE should be preceded by the WITH keyword; subsequent CTEs follow without additional WITH keywords.
  5. Referencing the CTE
    After the CTE definition, you can write your main SQL query. Use the CTE’s name to refer to it just as you would with a regular table or view.

Here’s an example of a simple CTE that selects data from a table named orders and filters it only to include orders from the year 2022:

WITH order_cte AS ( 
    SELECT order_id, customer_id, order_date, total_amount 
    FROM orders 
    WHERE YEAR(order_date) = 2022 
)
-- Use the CTE in the main query as if it were a table or view 
SELECT * 
FROM order_cte;

In this example, the CTE is named order_cte and includes four columns from the orders table. The query in the CTE uses the YEAR function to filter the orders by year. Finally, the main query selects all columns from the CTE.

Using CoginitiScript Blocks as an Alternative to Common Table Expressions (CTEs)

In addition to traditional CTEs in SQL, Coginiti supports CoginitiScript, a powerful templating language that can be used to modularize and reuse SQL code. This method encapsulates SQL queries within named blocks, which can be called and parameterized within your SQL scripts, similar to invoking functions in programming languages.

Let’s see how you can translate the use of a CTE into a CoginitiScript block.

Defining a Simple Block

A block in CoginitiScript allows you to define a snippet of SQL code that you can reuse in your main query. Let’s take the previous CTE example and convert it into a CoginitiScript block:

#+src sql OrderInfo(year)
#+meta { :doc "Selects orders from a specified year." }
#+begin
  SELECT order_id, customer_id, order_date, total_amount 
  FROM orders 
  WHERE YEAR(order_date) = '{{year}}'
#+end

And then you can use this block in your main query like so:

SELECT * 
FROM {{ OrderInfo(2022) }};

In this example, the OrderInfo block acts similarly to a CTE, where it encapsulates the logic for selecting orders from a specific year. However, with CoginitiScript, this block is parameterized, making it more flexible as you can pass different years to get different results.

Advantages over Traditional CTEs

While both CTEs and CoginitiScript blocks allow for breaking down complex queries into simpler parts, blocks in CoginitiScript offer several advantages:

  • Parameterization: Blocks can accept parameters, making them highly versatile for different use cases without rewriting the SQL logic.
  • Reusability: Once defined, blocks can be used across different scripts, not just within the same query.
  • Maintainability: Encapsulating SQL logic in blocks promotes better organization and separation of concerns, which can simplify maintenance and updates.
  • Extended Capabilities: CoginitiScript also supports additional features such as constants, macros, conditional logic, and iteration within blocks, enabling dynamic construction of queries based on conditions and looping over elements, which is not directly possible with traditional CTEs.
Publication and Testing

Another unique feature is the ability to publish the results of a block as a database table or view using the #+meta directive with a :publication key. This can significantly enhance performance by caching results for future use:

#+src sql OrderData()
#+meta {
  :publication {
    :type "table",
    :name "order_data",
    :schema "analytics"
  }
}
#+begin
  SELECT * FROM orders WHERE order_date >= '2022-01-01'
#+end

Furthermore, with CoginitiScript’s testing capabilities, you can ensure the integrity of your data before publication:

#+import "std/test"
#+test sql ValidOrderData()
#+begin
SELECT * FROM order_data WHERE total_amount < 0
#+end

{{ test.Run(tests=[ValidOrderData]) }}

This block will check for any orders with a negative total amount, which typically indicates an error.

Conclusion

By incorporating CoginitiScript blocks into your SQL workflow, you can enjoy a more modular, flexible, and maintainable approach to writing and managing SQL code compared to traditional CTEs. This makes it an attractive alternative, especially for complex or frequently-changing datasets.

Download Coginiti Pro to try it for yourself!