Mastering BigQuery’s Pipe Syntax: Streamlining Your SQL Queries

Free AI web copilot to create summaries, insights and extended knowledge, download it at here
5721
Abstract
ing the entire query.</li><li><b>Simplified Debugging</b>: Analyzing intermediate results is more manageable, as you can inspect the output after each step.</li><li><b>Enhanced Extensibility</b>: Extending SQL with new operations or functions becomes more intuitive and less prone to syntax conflicts.</li><li><b>Alignment with Logical Data Flow</b>: The order of operations in your query matches the actual data processing sequence.</li></ul><h1 id="bc85">Getting Started with Pipe Syntax in BigQuery</h1><p id="ce2c">To use Pipe Syntax, you begin your query with a <code>FROM</code> clause and then chain subsequent operations using the <code>|></code> operator. Each pipe operator represents a specific transformation.</p><p id="aa49"><b>Basic Structure:</b></p><div id="e4ae"><pre><span class="hljs-keyword">FROM</span> table_name
<span class="hljs-operator">|</span><span class="hljs-operator">></span> operation1
<span class="hljs-operator">|</span><span class="hljs-operator">></span> operation2
<span class="hljs-operator">|</span><span class="hljs-operator">></span> ...</pre></div><p id="2f31"><b>Available Pipe Operators:</b></p><ul><li><code>SELECT</code>: Select specific columns.</li><li><code>WHERE</code>: Filter rows based on conditions.</li><li><code>JOIN</code>: Join with another table.</li><li><code>AGGREGATE</code>: Perform aggregations.</li><li><code>ORDER BY</code>: Sort the results.</li><li><code>LIMIT</code>: Limit the number of rows.</li><li><code>EXTEND</code>: Add computed columns.</li><li><code>DROP</code>: Remove columns.</li><li><code>SET</code>: Update column values.</li><li><code>CALL</code>: Invoke table-valued functions.</li><li>And more…</li></ul><h1 id="beb0">Key Points:</h1><ul><li><b>Flexible Ordering</b>: Operators can be applied in any order, any number of times.</li><li><b>Independent Operations</b>: Each operator works independently, making it easy to understand and modify.</li><li><b>Consistent Scoping</b>: Operators only have access to the immediate input table and their arguments, ensuring clear and predictable behavior.</li></ul><h1 id="013d">Real-World Use Case: Analyzing E-commerce Orders</h1><p id="a19d">Let’s apply Pipe Syntax to a practical example using the <code>bigquery-public-data.thelook_ecommerce.order_items</code> dataset.</p><h2 id="6fb9">Objective:</h2><p id="b1cb">We want to analyze the total sales and number of orders per day for ‘Completed’ orders and find the top 5 days with the highest sales.</p><p id="3a05"><b>Traditional SQL Query:</b></p><div id="0b9d"><pre><span class="hljs-keyword">SELECT</span>
<span class="hljs-type">DATE</span>(created_at) <span class="hljs-keyword">AS</span> order_date,
<span class="hljs-built_in">COUNT</span>(<span class="hljs-operator"></span>) <span class="hljs-keyword">AS</span> total_orders,
<span class="hljs-built_in">SUM</span>(sale_price) <span class="hljs-keyword">AS</span> total_sales
<span class="hljs-keyword">FROM</span>
bigquery<span class="hljs-operator">-</span>public<span class="hljs-operator">-</span>data.thelook_ecommerce.order_items
<span class="hljs-keyword">WHERE</span>
status <span class="hljs-operator">=</span> <span class="hljs-string">'Completed'</span>
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span>
order_date
<span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span>
total_sales <span class="hljs-keyword">DESC</span>
LIMIT
<span class="hljs-number">5</span>;</pre></div><p id="fde6"><b>Refactoring Using Pipe Syntax:</b></p><div id="4210"><pre><span class="hljs-keyword">FROM</span> bigquery-<span class="hljs-keyword">public</span>-data.thelook_ecommerce.order_items
|> <span class="hljs-keyword">WHERE</span> status = <span class="hljs-comment">'Completed'</span>
|> EXTEND <span class="hljs-type">DATE</span>(created_at) <span class="hljs-keyword">AS</span> order_date
|> <span class="hljs-keyword">AGGREGATE</span>
COUNT() <span class="hljs-keyword">AS</span> total_orders,
SUM(sale_price) <span class="hljs-keyword">AS</span> total_sales
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> order_date
|> <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> total_sales DESC
|> LIMIT <span class="hljs-number">5</span>;</pre></div><h2 id="c062">Detailed Explanation of the Pipe Syntax Query</h2><p id="79d5">Let’s dissect each part of the Pipe Syntax query:</p><p id="d02e"><b>Starting Point:</b></p><div id="7a1e"><pre>FROM bigquery-<span class="hljs-keyword">public</span>-<span class="hljs-keyword">data</span>.thelook_ecommerce.order_items</pre></div><ul><li>We begin by selecting the <code>order_items</code> table.</li></ul><p id="67b5"><b>Filtering Rows:</b></p><div id="b5e2"><pre>|> <span class="hljs-type">WHERE</span> <span class="hljs-variable">status</span> <span class="hljs-operator">=</span> <span class="hljs-string">'Completed'</span></pre></div><ul><li>Filters the dataset to include only rows where the <code>status</code> is 'Completed'.</li></ul><p id="e50a"><b>Adding Computed Column:</b></p><div id="6408"><pre>|> EXTEND <span class="hljs-type">DATE</span>(created_at) <span class="hljs-keyword">AS</span> order_date</pre></div><ul><li>Adds a new column <code>order_date</code> by extracting the date from the <code>created_at</code> timestamp.</li></ul><p id="9dbd"><b>Aggregating Data:</b></p><div id="b22c"><pre>|> <span class="hljs-keyword">AGGREGATE</span>
COUNT(*) <span class="hljs-keyword">AS</span> total_orders,
SUM(sale_price) <span class="hljs-keyword">AS</span> total_sales
<span class="hljs-keyword">GROUP</span> <span class="hlj
Options
s-keyword">BY</span> order_date</pre></div><ul><li>Groups the data by <code>order_date</code> and calculates the <code>total_orders</code> and <code>total_sales</code> for each date.</li></ul><p id="7a36"><b>Sorting Results:</b></p><div id="17e8"><pre><span class="hljs-operator">|</span><span class="hljs-operator">></span> <span class="hljs-keyword">ORDER</span> <span class="hljs-keyword">BY</span> total_sales <span class="hljs-keyword">DESC</span></pre></div><ul><li>Orders the results in descending order of <code>total_sales</code>.</li></ul><p id="651c"><b>Limiting Output:</b></p><div id="d143"><pre>|> <span class="hljs-variable constant_">LIMIT</span> <span class="hljs-number">5</span>;</pre></div><ul><li>Limits the output to the top 5 records.</li></ul><h2 id="e11e">Benefits Highlighted:</h2><ul><li><b>Sequential Flow</b>: Each operation builds on the previous one in a logical sequence.</li><li><b>Simplified Syntax</b>: Eliminates the need for nested subqueries and repetitive clauses.</li><li><b>Enhanced Clarity</b>: Easier to read and understand compared to the traditional SQL version.</li></ul><h1 id="0c8b">Additional Examples</h1><h2 id="4d6c">Calculating Average Sale Price Per Status</h2><p id="89df"><b>Objective:</b> Find the average sale price for each order status.</p><p id="0d0b"><b>Traditional SQL:</b></p><div id="18ae"><pre><span class="hljs-keyword">SELECT</span>
status,
AVG(sale_price) <span class="hljs-keyword">AS</span> average_sale_price
<span class="hljs-keyword">FROM</span>
bigquery-<span class="hljs-keyword">public</span>-data.thelook_ecommerce.order_items
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span>
status;</pre></div><p id="00be"><b>Pipe Syntax:</b></p><div id="9a5f"><pre><span class="hljs-keyword">FROM</span> bigquery-<span class="hljs-keyword">public</span>-data.thelook_ecommerce.order_items
|> <span class="hljs-keyword">AGGREGATE</span>
AVG(sale_price) <span class="hljs-keyword">AS</span> average_sale_price
<span class="hljs-keyword">GROUP</span> <span class="hljs-keyword">BY</span> status;</pre></div><p id="26d5"><b>Explanation:</b></p><ul><li><b>AGGREGATE Operator</b>: Performs the aggregation and grouping in a single, concise operation.</li><li><b>Clarity</b>: Removes redundancy by eliminating the need to reference <code>status</code> in both <code>SELECT</code> and <code>GROUP BY</code>.</li></ul><h2 id="2588">Identifying Delayed Shipments</h2><p id="8a00"><b>Objective:</b> List orders where the shipping date is more than 7 days after the order creation date.</p><p id="20ce"><b>Traditional SQL:</b></p><div id="98df"><pre><span class="hljs-keyword">SELECT</span>
order_id,
user_id,
created_at,
shipped_at,
DATE_DIFF(shipped_at, created_at, <span class="hljs-keyword">DAY</span>) <span class="hljs-keyword">AS</span> days_to_ship
<span class="hljs-keyword">FROM</span>
bigquery<span class="hljs-operator">-</span>public<span class="hljs-operator">-</span>data.thelook_ecommerce.order_items
<span class="hljs-keyword">WHERE</span>
DATE_DIFF(shipped_at, created_at, <span class="hljs-keyword">DAY</span>) <span class="hljs-operator">></span> <span class="hljs-number">7</span>;</pre></div><p id="039f"><b>Pipe Syntax:</b></p><div id="83a1"><pre><span class="hljs-keyword">FROM</span> bigquery-<span class="hljs-keyword">public</span>-data.thelook_ecommerce.order_items
|> EXTEND
DATE_DIFF(shipped_at, created_at, DAY) <span class="hljs-keyword">AS</span> days_to_ship
|> <span class="hljs-keyword">WHERE</span> days_to_ship > <span class="hljs-number">7</span>
|> <span class="hljs-keyword">SELECT</span>
order_id,
user_id,
created_at,
shipped_at,
days_to_ship;</pre></div><p id="7cbf"><b>Explanation:</b></p><ul><li><b>Compute New Column</b>: <code>EXTEND</code> calculates <code>days_to_ship</code> and adds it to the dataset.</li><li><b>Filter Rows</b>: <code>WHERE</code> filters rows where <code>days_to_ship</code> is greater than 7.</li><li><b>Select Desired Columns</b>: <code>SELECT</code> picks specific columns for the final output.</li></ul><p id="71aa"><b>Advantages:</b></p><ul><li><b>Intermediate Computation</b>: Allows you to compute <code>days_to_ship</code> and use it immediately in the <code>WHERE</code> clause.</li><li><b>Modularity</b>: Each step is independent, making it easier to debug and modify.</li></ul><h1 id="d836">Conclusion</h1><p id="6051">BigQuery’s Pipe Syntax modernizes SQL by making it more intuitive and easier to work with, without sacrificing its strengths or deviating from its foundational principles. By adopting Pipe Syntax, you can write cleaner, more maintainable queries that align closely with the logical flow of data transformations.</p><h2 id="032c">Key Takeaways:</h2><ul><li><b>Sequential Transformation</b>: Pipe Syntax lets you write queries that mirror the step-by-step data processing steps.</li><li><b>Enhanced Readability</b>: Reduces complexity by eliminating deep nesting and repetitive clauses.</li><li><b>Improved Maintainability</b>: Simplifies the addition or modification of query operations.</li></ul><p id="a400"><b>References:</b></p><ul><li>BigQuery SQL Reference: <a href="https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax">BigQuery SQL</a></li><li>Introduction to Pipe Syntax: <a href="https://cloud.google.com/blog/products/data-analytics/pipe-syntax-modernizing-sql-without-sacrificing-its-strengths">Modernizing SQL with Pipe Syntax</a></li><li>SQL Has Problems. We can Fix Them: <a href="https://research.google/pubs/sql-has-problems-we-can-fix-them-pipe-syntax-in-sql/">Pipe Syntax in SQL</a></li></ul></article></body>

Google BigQuery is a powerful data warehouse that allows you to analyze massive datasets using SQL. However, as datasets and business logic grow in complexity, SQL queries can become lengthy, nested, and difficult to read and maintain. To address these challenges, BigQuery introduces Pipe Syntax, a modern enhancement to SQL that simplifies query writing, improves readability, and maintains all the strengths of traditional SQL.
In this blog post, we’ll explore how you can leverage Pipe Syntax in BigQuery to streamline your SQL queries. We’ll use the BigQuery public dataset bigquery-public-data.thelook_ecommerce.order_items as our example.
SQL has been the de facto language for managing and analyzing relational databases for decades. While powerful, traditional SQL syntax can sometimes be:
For example, performing multi-level aggregations or applying transformations across different stages often results in deeply nested queries that are hard to interpret.
In traditional SQL, the syntactic order of clauses (SELECT, FROM, WHERE, GROUP BY, ORDER BY) doesn't always align with the semantic order in which data is processed. This mismatch can make it challenging to understand the flow of data, especially in complex queries where subqueries are nested multiple levels deep.
Pipe Syntax is a feature in BigQuery that simplifies SQL queries by allowing you to chain operations using the pipe operator (|>). Inspired by functional programming and Unix pipelines, Pipe Syntax lets you express data transformations sequentially, making your queries more intuitive and easier to read.

Here’s a simple analogy: Imagine you’re assembling a lego-toy. Instead of following a complex, all-in-one instruction, you break it down into steps — connecting piece A to B, then B to C, and so on. Pipe syntax lets you do just that with your SQL queries.
Instead of nesting subqueries or dealing with deeply structured SQL, you start with a base dataset and apply transformations step by step, using the |> operator to chain operations. Each operation takes the output of the previous step as its input.
Traditional SQL Example:
SELECT ...
FROM (
SELECT ...
FROM (
SELECT ...
FROM table
WHERE ...
)
WHERE ...
)Equivalent Pipe Syntax:
FROM table
|> WHERE ...
|> SELECT ...
|> WHERE ...
|> SELECT ...In Pipe Syntax, each operation is composed in the order that it’s written, mirroring the logical flow of data transformations.
To use Pipe Syntax, you begin your query with a FROM clause and then chain subsequent operations using the |> operator. Each pipe operator represents a specific transformation.
Basic Structure:
FROM table_name
|> operation1
|> operation2
|> ...Available Pipe Operators:
SELECT: Select specific columns.WHERE: Filter rows based on conditions.JOIN: Join with another table.AGGREGATE: Perform aggregations.ORDER BY: Sort the results.LIMIT: Limit the number of rows.EXTEND: Add computed columns.DROP: Remove columns.SET: Update column values.CALL: Invoke table-valued functions.Let’s apply Pipe Syntax to a practical example using the bigquery-public-data.thelook_ecommerce.order_items dataset.
We want to analyze the total sales and number of orders per day for ‘Completed’ orders and find the top 5 days with the highest sales.
Traditional SQL Query:
SELECT
DATE(created_at) AS order_date,
COUNT(*) AS total_orders,
SUM(sale_price) AS total_sales
FROM
`bigquery-public-data.thelook_ecommerce.order_items`
WHERE
status = 'Completed'
GROUP BY
order_date
ORDER BY
total_sales DESC
LIMIT
5;Refactoring Using Pipe Syntax:
FROM `bigquery-public-data.thelook_ecommerce.order_items`
|> WHERE status = 'Completed'
|> EXTEND DATE(created_at) AS order_date
|> AGGREGATE
COUNT(*) AS total_orders,
SUM(sale_price) AS total_sales
GROUP BY order_date
|> ORDER BY total_sales DESC
|> LIMIT 5;Let’s dissect each part of the Pipe Syntax query:
Starting Point:
FROM `bigquery-public-data.thelook_ecommerce.order_items`order_items table.Filtering Rows:
|> WHERE status = 'Completed'status is 'Completed'.Adding Computed Column:
|> EXTEND DATE(created_at) AS order_dateorder_date by extracting the date from the created_at timestamp.Aggregating Data:
|> AGGREGATE
COUNT(*) AS total_orders,
SUM(sale_price) AS total_sales
GROUP BY order_dateorder_date and calculates the total_orders and total_sales for each date.Sorting Results:
|> ORDER BY total_sales DESCtotal_sales.Limiting Output:
|> LIMIT 5;Objective: Find the average sale price for each order status.
Traditional SQL:
SELECT
status,
AVG(sale_price) AS average_sale_price
FROM
`bigquery-public-data.thelook_ecommerce.order_items`
GROUP BY
status;Pipe Syntax:
FROM `bigquery-public-data.thelook_ecommerce.order_items`
|> AGGREGATE
AVG(sale_price) AS average_sale_price
GROUP BY status;Explanation:
status in both SELECT and GROUP BY.Objective: List orders where the shipping date is more than 7 days after the order creation date.
Traditional SQL:
SELECT
order_id,
user_id,
created_at,
shipped_at,
DATE_DIFF(shipped_at, created_at, DAY) AS days_to_ship
FROM
`bigquery-public-data.thelook_ecommerce.order_items`
WHERE
DATE_DIFF(shipped_at, created_at, DAY) > 7;Pipe Syntax:
FROM `bigquery-public-data.thelook_ecommerce.order_items`
|> EXTEND
DATE_DIFF(shipped_at, created_at, DAY) AS days_to_ship
|> WHERE days_to_ship > 7
|> SELECT
order_id,
user_id,
created_at,
shipped_at,
days_to_ship;Explanation:
EXTEND calculates days_to_ship and adds it to the dataset.WHERE filters rows where days_to_ship is greater than 7.SELECT picks specific columns for the final output.Advantages:
days_to_ship and use it immediately in the WHERE clause.BigQuery’s Pipe Syntax modernizes SQL by making it more intuitive and easier to work with, without sacrificing its strengths or deviating from its foundational principles. By adopting Pipe Syntax, you can write cleaner, more maintainable queries that align closely with the logical flow of data transformations.
References:
ChristianlauerUse BigQuery Storage Optimization for Apache Iceberg Tables
Vijay GadhaveNote: If you’re not a medium member, CLICK HERE
Zach QuinnNever write another schema, save on storage costs and more.
Jacob BennettTools I use that are cheaper than Netflix
Yerachmiel FeltzmanWhile adhering to data pipeline design best practices