Core Platform

Simplify SQL Workflows With New Features: Flow (->>) and UNION BY NAME

As data systems grow more complex, developers are increasingly tasked with building scalable SQL workflows that are both powerful and easy to maintain. Writing complex SQL can be challenging, especially when a large problem must be broken down into subtasks and then consolidated to generate a final result. This process often involves writing intricate Common Table Expressions (CTEs), storing intermediate results in temporary tables, using RESULT_SCAN() or carefully aggregating data from disparate tables. Fortunately, the following new SQL features can significantly simplify your experience:

Chaining your commands with the Flow operator (->>)

We often need to run multiple SQL statements that rely on the results of the previously executed statement. This has typically involved steps such as writing intermediate results in temporary table(s), using RESULT_SCAN(), creating complex subqueries and so on. The new Flow operator (->>) simplifies this frequently encountered scenario. This operator behaves like Unix pipes, but for SQL. It lets you chain multiple SQL statements together, where each step’s output can be used by any of the future steps in the chain. 

The benefits

  • Cleaner code: Your multistep logic becomes a single, readable pipeline.

  • Less clutter: No more writing intermediate results to temporary tables or using RESULT_SCAN().

  • Easy chaining: Use $1, $2 and so on to refer to the results of previous statements in the chain.

  • Flexibility: Works with SHOW, SELECT, DML statements and more.

Example: Analyzing sales data

Let's say you're a sales analyst trying to find your top-performing products in North America. First, let’s create some tables and add sample data.

CREATE OR REPLACE TABLE sales_by_region (
    product_name VARCHAR,
    region VARCHAR,
    sales_amount DECIMAL(10, 2)
);

INSERT INTO sales_by_region VALUES
    ('SuperWidget', 'North America', 1501.00),
    ('MegaWidget', 'North America', 1500.00),
    ('GigaWidget', 'Europe', 3500.00),
    ('MegaWidget', 'South America', 1050.50);
CREATE OR REPLACE TABLE sales_by_date (
    prod VARCHAR(50),
    sales_amt DECIMAL(10, 2),
    sold_date DATE
);

INSERT INTO sales_by_date (prod, sales_amt, sold_date) VALUES
('SuperWidget', 500.25, '2025-06-10'),
('MegaWidget', 2550.50, '2025-06-11'),
('SuperWidget', 1000.75, '2025-06-12'),
('GigaWidget', 3500.00, '2025-06-15');
CREATE OR REPLACE TABLE inventory (
    prod VARCHAR(50),
    location VARCHAR(50),
    qty_avail INT,
    last_updated DATE
);

INSERT INTO inventory (prod, location, qty_avail, last_updated) VALUES
('SuperWidget', 'Warehouse A', 250, '2025-06-01'),
('MegaWidget', 'Warehouse B', 120, '2025-06-01'),
('HyperWidget', 'Warehouse A', 75, '2025-06-05'),
('SuperWidget', 'Warehouse C', 150, '2025-06-20');

Now, let’s build a simple query to illustrate the behavior of Flow operator:

SELECT product_name, SUM(sales_amount) as total_sales
FROM sales_by_region
WHERE region = 'North America'
GROUP BY product_name
->>
SELECT product_name, total_sales
FROM $1
ORDER BY total_sales DESC;

The first query calculates the sales, and ->> pipes those results directly into the second query for sorting. There is no need to fetch results via intermediate steps.

Let’s try another one:

SHOW TABLES LIKE 'sales_by_region' 
->> 
SHOW TABLES LIKE 'sales_by_date' 
->> 
SHOW TABLES LIKE 'inventory' 
->> 
SELECT "created_on", "database_name", "schema_name", "name", "rows" FROM $1 UNION ALL 
SELECT "created_on", "database_name", "schema_name", "name", "rows" FROM $2 UNION ALL 
SELECT "created_on", "database_name", "schema_name", "name", "rows" FROM $3;

In this example, multiple SHOW statements are chained together, with their results ultimately piped into a single SELECT statement using $1, $2 and $3.

Effortless data merging with UNION BY NAME

Traditionally, UNION matches columns by their position, forcing you to manually select and alias columns to line them up correctly. UNION BY NAME simplifies this error-prone process by matching columns by their name, not their position.

Why it matters

  • Schema evolution: Seamlessly handle tables where columns are added or reordered.

  • Automatic filling: Fills missing columns in one table with NULL values automatically.

  • No more manual aliasing: Avoids tedious and error-prone aliasing just to get a UNION to work.

Example: Consolidating product data

Imagine you're tracking product launches and inventory across two different systems. The schemas don't quite match up. Your goal is to create a consolidated timeline of all product-related events.

Let’s build a simple query to illustrate the behavior of UNION BY NAME using the same set of tables created in the previous example.

SELECT
    prod,
    sales_amt,
    sold_date AS event_date,
    'sale' AS event_type
FROM sales_by_date

UNION BY NAME

SELECT
    prod,
    location,
    qty_avail,
    last_updated AS event_date,
    'inventory' AS event_type
FROM inventory

ORDER BY event_date DESC;

The result is a timeline mixing sales and inventory events, with columns such as location, qty_avail and sales_amt correctly aligned and populated with NULLs where they don't exist.

Putting it all together: Flow and UNION BY NAME

Let’s imagine you need to create a consolidated alert list that highlights both high-value sales and products with high stock levels. This involves filtering data from two different tables and then combining them into a single report.

Here’s how you can achieve this using a combination of the Flow operator and UNION BY NAME:

-- Step 1: Identify all products with high-value sales (sales > $2500)
SELECT
    prod,
    'High-Value Sale' as flag,
    sold_date as activity_date
FROM sales_by_date
WHERE sales_amt > 2500

-- Step 2: Pipe the high-value products and UNION them BY NAME with high-stock products (qty >= 150)
->>
(
    SELECT * FROM $1 -- This refers to the high-value sales
    UNION BY NAME
    SELECT
        prod,
        'High-Stock Item' as flag,
        last_updated as activity_date
    FROM inventory
    WHERE qty_avail >= 150
)

-- Step 3: Pipe the combined "alert list" into a final summary report
->>
SELECT
    prod,
    COUNT(*) as alert_count,
    LISTAGG(DISTINCT flag, ' | ') as alert_reasons
FROM $1 -- This refers to the result of the UNION BY NAME operation
GROUP BY prod
ORDER BY alert_count DESC, prod;

This powerful combination allows you to build complex data pipelines that integrate data from multiple sources and transform it efficiently, all within a clean and readable SQL structure.

To summarize

Feature Why it matters
->> (Flow operator) Cleanly chain SQL commands without needing temp tables or RESULT_SCAN.
UNION BY NAME Combine tables with different schemas without tedious manual aliasing.

Please feel free to play with these features in your environment and give us feedback. Additionally, we welcome your suggestions for innovative features you'd like us to develop next.

Share Article

Subscribe to our blog newsletter

Get the best, coolest and latest delivered to your inbox each week

Where Data Does More

  • 30-day free trial
  • No credit card required
  • Cancel anytime