Home Database SQL: Querying, Filtering, Joins, and Window Functions
Intermediate 3 min · July 17, 2026

SQL: Querying, Filtering, Joins, and Window Functions

Master Snowflake SQL with practical examples on querying, filtering, joins, and window functions.

N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Notes here come from systems that actually shipped.

Follow
Production
production tested
July 17, 2026
last updated
2,439
articles · all by Naren
Before you start⏱ 15-20 min read
  • Basic understanding of SQL (SELECT, WHERE, JOIN, GROUP BY).
  • Familiarity with data warehousing concepts.
  • Access to a Snowflake account or trial environment.
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • Snowflake SQL extends standard SQL with features like time travel, zero-copy cloning, and semi-structured data support.
  • Filtering uses standard WHERE clause but benefits from automatic clustering and micro-partition pruning.
  • Joins in Snowflake are similar to standard SQL but optimized for large-scale data with automatic statistics.
  • Window functions are fully supported with efficient execution on massive datasets.
✦ Definition~90s read
What is SQL?

Snowflake SQL is a dialect of SQL used in the Snowflake data warehouse, extending standard SQL with features like Time Travel, zero-copy cloning, and semi-structured data support.

Think of Snowflake as a super-powered library where books (data) are stored in a magical way that makes finding any book incredibly fast, no matter how many books there are.
Plain-English First

Think of Snowflake as a super-powered library where books (data) are stored in a magical way that makes finding any book incredibly fast, no matter how many books there are. You can ask questions (queries) using a special language (SQL) that works almost exactly like the library's standard card catalog, but with extra tricks like looking at how books were organized yesterday (time travel) or making instant copies without using extra shelf space (zero-copy cloning).

Snowflake is a cloud-native data warehouse that has revolutionized how organizations handle large-scale analytics. While it uses standard SQL, Snowflake introduces unique features that enhance performance, scalability, and ease of use. This tutorial focuses on the core SQL operations you'll use daily: querying, filtering, joins, and window functions. You'll learn not just the syntax, but how to write efficient queries that leverage Snowflake's architecture. We'll start with basic SELECT statements and filtering, then move to joins across multiple tables, and finally dive into window functions for analytical queries. Each section includes production-ready examples and common pitfalls. By the end, you'll be able to write complex analytical queries that run efficiently on terabytes of data.

Basic Querying with SELECT

Snowflake's SELECT statement follows standard SQL but includes powerful extensions. Start with simple queries to explore your data. Use SELECT to see all columns, but in production, always specify columns to reduce I/O. Snowflake's columnar storage makes SELECT efficient only when you need all columns. Use LIMIT to preview data. Snowflake supports TOP and LIMIT, but LIMIT is more common. Example: SELECT order_id, customer_id, order_date FROM orders LIMIT 10;

basic_select.sqlSQL
1
2
3
4
-- Select specific columns with limit
SELECT order_id, customer_id, order_date
FROM orders
LIMIT 10;
Output
ORDER_ID | CUSTOMER_ID | ORDER_DATE
----------+-------------+------------
1001 | 5001 | 2024-01-01
1002 | 5002 | 2024-01-02
...
💡Use Fully Qualified Names
📊 Production Insight
Snowflake's automatic clustering can make SELECT * on large tables slow if the table is not well-clustered. Use SYSTEM$CLUSTERING_INFORMATION to check.
🎯 Key Takeaway
Always select specific columns and use LIMIT for exploration to minimize data scanned.

Filtering with WHERE

Filtering in Snowflake uses the standard WHERE clause with predicates. Snowflake's micro-partition pruning automatically skips irrelevant partitions based on the filter conditions. For optimal performance, filter on columns that are used in the clustering key. Use comparison operators, IN, BETWEEN, LIKE, and IS NULL. Snowflake also supports QUALIFY for filtering after window functions. Example: SELECT * FROM orders WHERE order_date >= '2024-01-01' AND order_date < '2024-02-01';

filtering.sqlSQL
1
2
3
4
5
6
-- Filter by date range
SELECT order_id, customer_id, order_date, total_amount
FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-01-31'
  AND total_amount > 100
ORDER BY total_amount DESC;
Output
ORDER_ID | CUSTOMER_ID | ORDER_DATE | TOTAL_AMOUNT
----------+-------------+------------+--------------
1050 | 5100 | 2024-01-15 | 500.00
1023 | 5050 | 2024-01-10 | 250.00
...
⚠ Avoid Functions on Filter Columns
📊 Production Insight
In production, use EXPLAIN to see if partition pruning is happening. Look for 'Partitions Scanned' in the query profile.
🎯 Key Takeaway
Filter on clustering key columns for best performance; avoid wrapping columns in functions.

Joins in Snowflake

Snowflake supports all standard join types: INNER, LEFT, RIGHT, FULL OUTER, CROSS, and NATURAL joins. It also supports LATERAL joins and ASOF joins for time-series data. For large tables, ensure join columns are of the same data type to avoid implicit casts. Snowflake's query optimizer automatically chooses join order and algorithm (hash join, merge join, etc.). Use EXPLAIN to see the join strategy. Example: SELECT c.customer_name, o.order_id, o.total_amount FROM customers c INNER JOIN orders o ON c.customer_id = o.customer_id;

joins.sqlSQL
1
2
3
4
5
6
7
-- Inner join with aggregation
SELECT c.customer_name, COUNT(o.order_id) AS order_count, SUM(o.total_amount) AS total_spent
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
WHERE o.order_date >= '2024-01-01'
GROUP BY c.customer_name
ORDER BY total_spent DESC;
Output
CUSTOMER_NAME | ORDER_COUNT | TOTAL_SPENT
---------------+-------------+-------------
Alice | 5 | 2500.00
Bob | 3 | 1500.00
...
🔥Use LATERAL for Complex Subqueries
📊 Production Insight
When joining very large tables, consider using a larger warehouse to speed up hash joins. Also, avoid joining on string columns with different collations.
🎯 Key Takeaway
Ensure join columns are indexed or clustered; use EXPLAIN to verify join algorithm.

Window Functions: ROW_NUMBER, RANK, DENSE_RANK

Window functions perform calculations across a set of rows related to the current row. They are essential for analytical queries. Snowflake supports all standard window functions: ROW_NUMBER, RANK, DENSE_RANK, NTILE, LEAD, LAG, FIRST_VALUE, LAST_VALUE, and aggregate functions with OVER clause. The PARTITION BY clause divides the result set into partitions, and ORDER BY defines the order within each partition. Example: SELECT customer_id, order_date, total_amount, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY order_date DESC) AS rn FROM orders;

window_functions.sqlSQL
1
2
3
4
5
6
7
8
-- Rank customers by total spending per month
SELECT customer_id, DATE_TRUNC('month', order_date) AS month,
       SUM(total_amount) AS monthly_total,
       RANK() OVER (PARTITION BY DATE_TRUNC('month', order_date) ORDER BY SUM(total_amount) DESC) AS rank
FROM orders
GROUP BY customer_id, month
QUALIFY rank <= 3
ORDER BY month, rank;
Output
CUSTOMER_ID | MONTH | MONTHLY_TOTAL | RANK
-------------+------------+---------------+------
5001 | 2024-01-01 | 3000.00 | 1
5002 | 2024-01-01 | 2500.00 | 2
5003 | 2024-01-01 | 2000.00 | 3
...
💡Use QUALIFY to Filter Window Results
📊 Production Insight
Window functions can be memory-intensive. For large partitions, ensure your warehouse has enough memory. Use ORDER BY with ROWS BETWEEN to control the frame.
🎯 Key Takeaway
Window functions are powerful for ranking and running totals; use QUALIFY for post-window filtering.

Aggregate Functions with OVER: Running Totals and Moving Averages

Aggregate functions like SUM, AVG, COUNT can be used with OVER to compute running totals, moving averages, and cumulative statistics. The frame clause (ROWS BETWEEN) defines which rows to include. Snowflake supports ROWS, RANGE, and GROUPS frames. Example: SELECT order_date, total_amount, SUM(total_amount) OVER (ORDER BY order_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total FROM orders;

running_total.sqlSQL
1
2
3
4
5
6
7
8
9
-- 7-day moving average of daily sales
SELECT order_date, daily_total,
       AVG(daily_total) OVER (ORDER BY order_date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS moving_avg_7d
FROM (
    SELECT order_date, SUM(total_amount) AS daily_total
    FROM orders
    GROUP BY order_date
) AS daily
ORDER BY order_date;
Output
ORDER_DATE | DAILY_TOTAL | MOVING_AVG_7D
------------+-------------+---------------
2024-01-01 | 1000.00 | 1000.00
2024-01-02 | 1500.00 | 1250.00
...
🔥Frame Defaults
📊 Production Insight
For large datasets, consider using a smaller warehouse or breaking the query into steps to avoid memory issues.
🎯 Key Takeaway
Use explicit frame clauses to control which rows are included in the window calculation.

Time Travel and Zero-Copy Cloning

Snowflake's Time Travel allows you to query historical data up to 90 days back (depending on edition). Use AT or BEFORE with a timestamp, offset, or query ID. Zero-copy cloning creates a copy of a table without duplicating data, useful for testing and backups. Example: SELECT * FROM orders AT (TIMESTAMP => '2024-01-15 10:00:00'::TIMESTAMP); CREATE OR REPLACE TABLE orders_backup CLONE orders;

time_travel.sqlSQL
1
2
3
4
5
-- Query data as of 1 hour ago
SELECT * FROM orders AT (OFFSET => -3600);

-- Clone a table for testing
CREATE OR REPLACE TABLE orders_dev CLONE orders;
⚠ Time Travel Costs
📊 Production Insight
Time Travel can be used to recover from DML mistakes without restoring from backup. Always test recovery procedures.
🎯 Key Takeaway
Time Travel is a lifesaver for accidental data changes; use zero-copy cloning for instant snapshots.

Best Practices for Performance

To get the best performance from Snowflake SQL: 1) Use clustering keys on large tables that are frequently filtered by certain columns. 2) Avoid SELECT * in production; specify only needed columns. 3) Use EXPLAIN to understand query plans. 4) Leverage materialized views for pre-aggregated data. 5) Use appropriate warehouse size; auto-suspend to save costs. 6) Use QUALIFY instead of subqueries for window function filtering. 7) Use CTEs for readability but be aware they are materialized differently in Snowflake.

best_practices.sqlSQL
1
2
3
4
5
6
7
8
9
10
11
-- Use CTE for readability and performance
WITH monthly_sales AS (
    SELECT DATE_TRUNC('month', order_date) AS month,
           SUM(total_amount) AS total
    FROM orders
    GROUP BY month
)
SELECT month, total,
       LAG(total) OVER (ORDER BY month) AS prev_month_total
FROM monthly_sales
ORDER BY month;
💡Use Result Caching
📊 Production Insight
Always monitor query performance using the QUERY_HISTORY view. Look for 'Bytes Scanned' and 'Partitions Scanned' to identify inefficiencies.
🎯 Key Takeaway
Performance tuning in Snowflake involves clustering, warehouse sizing, and understanding the query profile.
● Production incidentPOST-MORTEMseverity: high

The Case of the Disappearing Rows: Time Travel to the Rescue

Symptom
Users reported missing sales records for the last quarter. Queries returned fewer rows than expected.
Assumption
The developer assumed the data was permanently lost because the DELETE statement had been committed.
Root cause
The developer ran a DELETE statement without a WHERE clause, removing all rows from the sales table.
Fix
Used Snowflake's Time Travel feature to restore the table to a state before the deletion: CREATE OR REPLACE TABLE sales CLONE sales AT (TIMESTAMP => '2024-01-15 10:00:00'::TIMESTAMP);
Key lesson
  • Always use transactions and test DELETE statements with SELECT first.
  • Enable Time Travel retention (default 1 day, can be extended).
  • Use zero-copy cloning for instant backups before risky operations.
  • Implement role-based access control to limit destructive operations.
  • Set up automated snapshots or use Snowflake's fail-safe for long-term recovery.
Production debug guideSymptom to Action4 entries
Symptom · 01
Query runs slowly on large tables
Fix
Check query profile for full scans vs. micro-partition pruning. Use CLUSTERING INFORMATION to see if table is well-clustered.
Symptom · 02
Join returns unexpected results (duplicates or missing rows)
Fix
Verify join keys and data types. Use SELECT * to inspect intermediate results. Check for NULLs in join columns.
Symptom · 03
Window function produces wrong running total
Fix
Check ORDER BY and ROWS/RANGE specification. Ensure PARTITION BY includes correct columns.
Symptom · 04
Time Travel query fails or returns stale data
Fix
Verify Time Travel retention period. Use AT or BEFORE with correct timestamp or query ID.
★ Quick Debug Cheat SheetCommon Snowflake SQL issues and immediate fixes.
Query too slow
Immediate action
Check warehouse size and auto-suspend settings
Commands
SELECT * FROM INFORMATION_SCHEMA.QUERY_HISTORY WHERE QUERY_ID = '<id>';
ALTER WAREHOUSE my_wh SET WAREHOUSE_SIZE = 'X-LARGE';
Fix now
Increase warehouse size or add clustering key.
Duplicate rows after JOIN+
Immediate action
Check for one-to-many relationships
Commands
SELECT COUNT(*), COUNT(DISTINCT primary_key) FROM table;
SELECT * FROM table1 JOIN table2 ON ...;
Fix now
Use SELECT DISTINCT or aggregate before join.
Window function error+
Immediate action
Check syntax and frame clause
Commands
SELECT column, ROW_NUMBER() OVER (PARTITION BY col ORDER BY col2) AS rn FROM table;
SHOW FUNCTIONS LIKE 'ROW_NUMBER';
Fix now
Ensure PARTITION BY and ORDER BY are correct.
FeatureStandard SQLSnowflake SQL
Time TravelNot availableAT/BEFORE with timestamp or query ID
Zero-copy cloningNot availableCREATE TABLE ... CLONE
QUALIFY clauseNot availableFilters after window functions
ClusteringIndexesAutomatic clustering with optional keys
Semi-structured dataJSON functionsVARIANT type with path access
⚙ Quick Reference
7 commands from this guide
FileCommand / CodePurpose
basic_select.sqlSELECT order_id, customer_id, order_dateBasic Querying with SELECT
filtering.sqlSELECT order_id, customer_id, order_date, total_amountFiltering with WHERE
joins.sqlSELECT c.customer_name, COUNT(o.order_id) AS order_count, SUM(o.total_amount) AS...Joins in Snowflake
window_functions.sqlSELECT customer_id, DATE_TRUNC('month', order_date) AS month,Window Functions
running_total.sqlSELECT order_date, daily_total,Aggregate Functions with OVER
time_travel.sqlSELECT * FROM orders AT (OFFSET => -3600);Time Travel and Zero-Copy Cloning
best_practices.sqlWITH monthly_sales AS (Best Practices for Performance

Key takeaways

1
Snowflake SQL extends standard SQL with powerful features like Time Travel, zero-copy cloning, and QUALIFY.
2
Efficient filtering relies on clustering keys and avoiding functions on filter columns.
3
Window functions are essential for analytical queries; use QUALIFY for post-window filtering.
4
Performance optimization involves understanding query profiles, warehouse sizing, and using EXPLAIN.

Common mistakes to avoid

3 patterns
×

Using SELECT * in production queries

×

Forgetting to use QUALIFY and using subqueries instead

×

Joining on columns with different data types

INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01SENIOR
Explain the difference between ROW_NUMBER, RANK, and DENSE_RANK.
Q02SENIOR
How does Snowflake's Time Travel work and what are its limitations?
Q03SENIOR
Write a query to find the top 3 products by sales in each category using...
Q01 of 03SENIOR

Explain the difference between ROW_NUMBER, RANK, and DENSE_RANK.

ANSWER
ROW_NUMBER assigns a unique sequential integer to each row within a partition, starting at 1. RANK assigns the same rank to ties, but leaves gaps in the sequence. DENSE_RANK assigns the same rank to ties without gaps.
FAQ · 4 QUESTIONS

Frequently Asked Questions

01
What is the difference between QUALIFY and HAVING in Snowflake?
02
How do I optimize a slow query in Snowflake?
03
Can I use window functions with GROUP BY?
04
What is zero-copy cloning and when should I use it?
N
Naren Founder & Principal Engineer

20+ years shipping high-throughput database systems. Notes here come from systems that actually shipped.

Follow
Verified
production tested
July 17, 2026
last updated
2,439
articles · all by Naren
🔥

That's Snowflake. Mark it forged?

3 min read · try the examples if you haven't

Previous
Data Loading: Stages, COPY INTO, and File Formats
6 / 33 · Snowflake
Next
Time Travel, Zero-Copy Cloning, and Data Restoration