SQL Keywords

SQL Keywords

COUNT / SUM / AVG / MAX / MIN

Feb 23, 2026

·

5

min read

Category: Aggregate Functions

Platform Support:

✅ Snowflake | ✅ BigQuery | ✅ Databricks

Description

Core aggregate functions that compute summary values across rows. COUNT counts rows, SUM adds values, AVG calculates average, MAX finds maximum, and MIN finds minimum. Essential for data analysis, reporting, and statistical calculations.

Syntax

COUNT(*) | COUNT(column) | COUNT(DISTINCT column)
SUM(column)
AVG(column)
MAX(column)
MIN(column)
COUNT(*) | COUNT(column) | COUNT(DISTINCT column)
SUM(column)
AVG(column)
MAX(column)
MIN(column)
COUNT(*) | COUNT(column) | COUNT(DISTINCT column)
SUM(column)
AVG(column)
MAX(column)
MIN(column)

Platform-Specific Notes

All Platforms:

  • Standard SQL aggregate functions

  • Identical behavior across platforms

  • Ignore NULL values (except COUNT(*))

  • Used with GROUP BY for grouped aggregation

Example 1: Basic Aggregations

All Platforms:

SELECT 
    COUNT(*) as total_orders,
    COUNT(DISTINCT customer_id) as unique_customers,
    SUM(total) as total_revenue,
    AVG(total) as average_order_value,
    MAX(total) as largest_order,
    MIN(total) as smallest_order,
    MAX(order_date) as most_recent_order,
    MIN(order_date) as first_order
FROM

SELECT 
    COUNT(*) as total_orders,
    COUNT(DISTINCT customer_id) as unique_customers,
    SUM(total) as total_revenue,
    AVG(total) as average_order_value,
    MAX(total) as largest_order,
    MIN(total) as smallest_order,
    MAX(order_date) as most_recent_order,
    MIN(order_date) as first_order
FROM

SELECT 
    COUNT(*) as total_orders,
    COUNT(DISTINCT customer_id) as unique_customers,
    SUM(total) as total_revenue,
    AVG(total) as average_order_value,
    MAX(total) as largest_order,
    MIN(total) as smallest_order,
    MAX(order_date) as most_recent_order,
    MIN(order_date) as first_order
FROM

Sample Data (orders table):

order_id

customer_id

order_date

total

101

1

2024-01-15

250.00

102

2

2024-01-16

180.00

103

1

2024-01-20

320.00

104

3

2024-01-22

450.00

105

2

2024-01-25

290.00

Result:

total_orders

unique_customers

total_revenue

average_order_value

largest_order

smallest_order

most_recent_order

first_order

5

3

1490.00

298.00

450.00

180.00

2024-01-25

2024-01-15

Example 2: GROUP BY with Aggregates

All Platforms:

SELECT 
    department,
    COUNT(*) as employee_count,
    SUM(salary) as total_payroll,
    AVG(salary) as avg_salary,
    MAX(salary) as highest_salary,
    MIN(salary) as lowest_salary,
    MAX(salary) - MIN(salary) as salary_range
FROM employees
GROUP BY department
ORDER BY total_payroll DESC

SELECT 
    department,
    COUNT(*) as employee_count,
    SUM(salary) as total_payroll,
    AVG(salary) as avg_salary,
    MAX(salary) as highest_salary,
    MIN(salary) as lowest_salary,
    MAX(salary) - MIN(salary) as salary_range
FROM employees
GROUP BY department
ORDER BY total_payroll DESC

SELECT 
    department,
    COUNT(*) as employee_count,
    SUM(salary) as total_payroll,
    AVG(salary) as avg_salary,
    MAX(salary) as highest_salary,
    MIN(salary) as lowest_salary,
    MAX(salary) - MIN(salary) as salary_range
FROM employees
GROUP BY department
ORDER BY total_payroll DESC

Sample Data (employees table):

employee_id

name

department

salary

1

Alice

Sales

75000

2

Bob

Sales

65000

3

Carol

Sales

70000

4

David

IT

95000

5

Emma

IT

92000

6

Frank

IT

88000

7

Grace

Marketing

72000

Result:

department

employee_count

total_payroll

avg_salary

highest_salary

lowest_salary

salary_range

IT

3

275000

91666.67

95000

88000

7000

Sales

3

210000

70000.00

75000

65000

10000

Marketing

1

72000

72000.00

72000

72000

0

Example 3: COUNT Variations

All Platforms:

SELECT 
    COUNT(*) as all_rows,                    -- Counts all rows including NULLs
    COUNT(email) as rows_with_email,         -- Counts non-NULL emails
    COUNT(DISTINCT email) as unique_emails,  -- Counts unique emails
    COUNT(phone) as rows_with_phone,
    COUNT(*) - COUNT(email) as missing_emails,
    COUNT(*) - COUNT(phone) as missing_phones
FROM

SELECT 
    COUNT(*) as all_rows,                    -- Counts all rows including NULLs
    COUNT(email) as rows_with_email,         -- Counts non-NULL emails
    COUNT(DISTINCT email) as unique_emails,  -- Counts unique emails
    COUNT(phone) as rows_with_phone,
    COUNT(*) - COUNT(email) as missing_emails,
    COUNT(*) - COUNT(phone) as missing_phones
FROM

SELECT 
    COUNT(*) as all_rows,                    -- Counts all rows including NULLs
    COUNT(email) as rows_with_email,         -- Counts non-NULL emails
    COUNT(DISTINCT email) as unique_emails,  -- Counts unique emails
    COUNT(phone) as rows_with_phone,
    COUNT(*) - COUNT(email) as missing_emails,
    COUNT(*) - COUNT(phone) as missing_phones
FROM

Sample Data (customers table):

customer_id

name

email

phone

1

John

john@email.com

555-1234

2

Maria

maria@email.com

NULL

3

Sarah

NULL

555-5678

4

Bob

bob@email.com

555-9012

5

Alice

NULL

NULL

Result:

all_rows

rows_with_email

unique_emails

rows_with_phone

missing_emails

missing_phones

5

3

3

3

2

2

Example 4: Conditional Aggregation

All Platforms:

SELECT 
    product_category,
    COUNT(*) as total_products,
    COUNT(CASE WHEN in_stock = TRUE THEN 1 END) as in_stock_count,
    COUNT(CASE WHEN in_stock = FALSE THEN 1 END) as out_of_stock_count,
    SUM(CASE WHEN price > 100 THEN 1 ELSE 0 END) as premium_products,
    AVG(CASE WHEN in_stock = TRUE THEN price END) as avg_price_in_stock,
    MAX(CASE WHEN in_stock = TRUE THEN price END) as max_available_price
FROM products
GROUP BY

SELECT 
    product_category,
    COUNT(*) as total_products,
    COUNT(CASE WHEN in_stock = TRUE THEN 1 END) as in_stock_count,
    COUNT(CASE WHEN in_stock = FALSE THEN 1 END) as out_of_stock_count,
    SUM(CASE WHEN price > 100 THEN 1 ELSE 0 END) as premium_products,
    AVG(CASE WHEN in_stock = TRUE THEN price END) as avg_price_in_stock,
    MAX(CASE WHEN in_stock = TRUE THEN price END) as max_available_price
FROM products
GROUP BY

SELECT 
    product_category,
    COUNT(*) as total_products,
    COUNT(CASE WHEN in_stock = TRUE THEN 1 END) as in_stock_count,
    COUNT(CASE WHEN in_stock = FALSE THEN 1 END) as out_of_stock_count,
    SUM(CASE WHEN price > 100 THEN 1 ELSE 0 END) as premium_products,
    AVG(CASE WHEN in_stock = TRUE THEN price END) as avg_price_in_stock,
    MAX(CASE WHEN in_stock = TRUE THEN price END) as max_available_price
FROM products
GROUP BY

Sample Data (products table):

product_id

product_name

product_category

price

in_stock

1

Laptop

Electronics

999

TRUE

2

Mouse

Electronics

29

TRUE

3

Monitor

Electronics

349

FALSE

4

Desk

Furniture

299

TRUE

5

Chair

Furniture

199

TRUE

Result:

product_category

total_products

in_stock_count

out_of_stock_count

premium_products

avg_price_in_stock

max_available_price

Electronics

3

2

1

2

514.00

999

Furniture

2

2

0

2

249.00

299

Example 5: Time-Based Aggregation

All Platforms:

SELECT 
    DATE_TRUNC('MONTH', sale_date) as month,
    COUNT(*) as transaction_count,
    COUNT(DISTINCT customer_id) as unique_customers,
    SUM(amount) as monthly_revenue,
    AVG(amount) as avg_transaction,
    MAX(amount) as largest_sale,
    MIN(amount) as smallest_sale,
    SUM(amount) / COUNT(DISTINCT customer_id) as revenue_per_customer
FROM sales
GROUP BY DATE_TRUNC('MONTH', sale_date)
ORDER BY month

SELECT 
    DATE_TRUNC('MONTH', sale_date) as month,
    COUNT(*) as transaction_count,
    COUNT(DISTINCT customer_id) as unique_customers,
    SUM(amount) as monthly_revenue,
    AVG(amount) as avg_transaction,
    MAX(amount) as largest_sale,
    MIN(amount) as smallest_sale,
    SUM(amount) / COUNT(DISTINCT customer_id) as revenue_per_customer
FROM sales
GROUP BY DATE_TRUNC('MONTH', sale_date)
ORDER BY month

SELECT 
    DATE_TRUNC('MONTH', sale_date) as month,
    COUNT(*) as transaction_count,
    COUNT(DISTINCT customer_id) as unique_customers,
    SUM(amount) as monthly_revenue,
    AVG(amount) as avg_transaction,
    MAX(amount) as largest_sale,
    MIN(amount) as smallest_sale,
    SUM(amount) / COUNT(DISTINCT customer_id) as revenue_per_customer
FROM sales
GROUP BY DATE_TRUNC('MONTH', sale_date)
ORDER BY month

Sample Result:

month

transaction_count

unique_customers

monthly_revenue

avg_transaction

largest_sale

smallest_sale

revenue_per_customer

2024-01-01

450

280

125000

277.78

2500

15

446.43

2024-02-01

520

310

142000

273.08

3000

10

458.06

Example 6: Nested Aggregations

All Platforms:

-- Average of department averages
WITH dept_stats AS (
    SELECT 
        department,
        AVG(salary) as dept_avg_salary,
        COUNT(*) as dept_employee_count
    FROM employees
    GROUP BY department
)
SELECT 
    AVG(dept_avg_salary) as company_avg_of_dept_avgs,
    MAX(dept_avg_salary) as highest_dept_avg,
    MIN(dept_avg_salary) as lowest_dept_avg,
    SUM(dept_employee_count) as total_employees,
    COUNT(*) as number_of_departments
FROM

-- Average of department averages
WITH dept_stats AS (
    SELECT 
        department,
        AVG(salary) as dept_avg_salary,
        COUNT(*) as dept_employee_count
    FROM employees
    GROUP BY department
)
SELECT 
    AVG(dept_avg_salary) as company_avg_of_dept_avgs,
    MAX(dept_avg_salary) as highest_dept_avg,
    MIN(dept_avg_salary) as lowest_dept_avg,
    SUM(dept_employee_count) as total_employees,
    COUNT(*) as number_of_departments
FROM

-- Average of department averages
WITH dept_stats AS (
    SELECT 
        department,
        AVG(salary) as dept_avg_salary,
        COUNT(*) as dept_employee_count
    FROM employees
    GROUP BY department
)
SELECT 
    AVG(dept_avg_salary) as company_avg_of_dept_avgs,
    MAX(dept_avg_salary) as highest_dept_avg,
    MIN(dept_avg_salary) as lowest_dept_avg,
    SUM(dept_employee_count) as total_employees,
    COUNT(*) as number_of_departments
FROM

NULL Handling

Important differences:

Function

NULL Behavior

Example

COUNT(*)

Counts NULLs

5 rows with 2 NULLs = 5

COUNT(column)

Ignores NULLs

5 rows with 2 NULLs = 3

SUM(column)

Ignores NULLs

SUM(10, 20, NULL) = 30

AVG(column)

Ignores NULLs

AVG(10, 20, NULL) = 15

MAX/MIN(column)

Ignores NULLs

MAX(10, 20, NULL) = 20

SELECT 
    COUNT(*) as total_rows,          -- 5
    COUNT(bonus) as non_null_bonus,  -- 3 (ignores 2 NULLs)
    SUM(bonus) as total_bonus,       -- 15000 (ignores NULLs)
    AVG(bonus) as avg_bonus,         -- 5000 (15000/3, not 15000/5)
    SUM(bonus) / COUNT(*) as avg_including_nulls  -- 3000 (15000/5)
FROM

SELECT 
    COUNT(*) as total_rows,          -- 5
    COUNT(bonus) as non_null_bonus,  -- 3 (ignores 2 NULLs)
    SUM(bonus) as total_bonus,       -- 15000 (ignores NULLs)
    AVG(bonus) as avg_bonus,         -- 5000 (15000/3, not 15000/5)
    SUM(bonus) / COUNT(*) as avg_including_nulls  -- 3000 (15000/5)
FROM

SELECT 
    COUNT(*) as total_rows,          -- 5
    COUNT(bonus) as non_null_bonus,  -- 3 (ignores 2 NULLs)
    SUM(bonus) as total_bonus,       -- 15000 (ignores NULLs)
    AVG(bonus) as avg_bonus,         -- 5000 (15000/3, not 15000/5)
    SUM(bonus) / COUNT(*) as avg_including_nulls  -- 3000 (15000/5)
FROM

Aggregate Function Combinations

All Platforms:

SELECT 
    -- Basic stats
    COUNT(*) as n,
    AVG(price) as mean,
    -- Variance calculation
    AVG(price * price) - (AVG(price) * AVG(price)) as variance,
    -- Standard deviation (approximate)
    SQRT(AVG(price * price) - (AVG(price) * AVG(price))) as std_dev,
    -- Coefficient of variation
    SQRT(AVG(price * price) - (AVG(price) * AVG(price))) / AVG(price) as cv,
    -- Range
    MAX(price) - MIN(price) as range
FROM

SELECT 
    -- Basic stats
    COUNT(*) as n,
    AVG(price) as mean,
    -- Variance calculation
    AVG(price * price) - (AVG(price) * AVG(price)) as variance,
    -- Standard deviation (approximate)
    SQRT(AVG(price * price) - (AVG(price) * AVG(price))) as std_dev,
    -- Coefficient of variation
    SQRT(AVG(price * price) - (AVG(price) * AVG(price))) / AVG(price) as cv,
    -- Range
    MAX(price) - MIN(price) as range
FROM

SELECT 
    -- Basic stats
    COUNT(*) as n,
    AVG(price) as mean,
    -- Variance calculation
    AVG(price * price) - (AVG(price) * AVG(price)) as variance,
    -- Standard deviation (approximate)
    SQRT(AVG(price * price) - (AVG(price) * AVG(price))) as std_dev,
    -- Coefficient of variation
    SQRT(AVG(price * price) - (AVG(price) * AVG(price))) / AVG(price) as cv,
    -- Range
    MAX(price) - MIN(price) as range
FROM

Window Functions with Aggregates

All Platforms:

SELECT 
    employee_name,
    department,
    salary,
    -- Department aggregates as window functions
    AVG(salary) OVER (PARTITION BY department) as dept_avg,
    MAX(salary) OVER (PARTITION BY department) as dept_max,
    MIN(salary) OVER (PARTITION BY department) as dept_min,
    COUNT(*) OVER (PARTITION BY department) as dept_size,
    -- Comparison to department stats
    salary - AVG(salary) OVER (PARTITION BY department) as diff_from_avg,
    salary / AVG(salary) OVER (PARTITION BY department) as ratio_to_avg
FROM employees
ORDER BY department, salary DESC

SELECT 
    employee_name,
    department,
    salary,
    -- Department aggregates as window functions
    AVG(salary) OVER (PARTITION BY department) as dept_avg,
    MAX(salary) OVER (PARTITION BY department) as dept_max,
    MIN(salary) OVER (PARTITION BY department) as dept_min,
    COUNT(*) OVER (PARTITION BY department) as dept_size,
    -- Comparison to department stats
    salary - AVG(salary) OVER (PARTITION BY department) as diff_from_avg,
    salary / AVG(salary) OVER (PARTITION BY department) as ratio_to_avg
FROM employees
ORDER BY department, salary DESC

SELECT 
    employee_name,
    department,
    salary,
    -- Department aggregates as window functions
    AVG(salary) OVER (PARTITION BY department) as dept_avg,
    MAX(salary) OVER (PARTITION BY department) as dept_max,
    MIN(salary) OVER (PARTITION BY department) as dept_min,
    COUNT(*) OVER (PARTITION BY department) as dept_size,
    -- Comparison to department stats
    salary - AVG(salary) OVER (PARTITION BY department) as diff_from_avg,
    salary / AVG(salary) OVER (PARTITION BY department) as ratio_to_avg
FROM employees
ORDER BY department, salary DESC

Common Use Cases

COUNT:

  1. Row counting: Total records, unique values

  2. Data quality: Missing values, duplicates

  3. Reporting: Customer counts, transaction volumes

SUM:

  1. Financial: Revenue, expenses, totals

  2. Inventory: Stock quantities

  3. Metrics: Page views, clicks, conversions

AVG:

  1. Performance: Average response time, ratings

  2. Business: Average order value, basket size

  3. Analytics: Mean metrics, benchmarks

MAX/MIN:

  1. Ranges: Price ranges, date ranges

  2. Extremes: Highest score, oldest record

  3. Thresholds: Peak usage, minimum stock

Performance Tips

  1. Index GROUP BY columns: Improves grouping performance

  2. Use APPROX_COUNT_DISTINCT: Faster for large datasets

  3. Filter before aggregating: Use WHERE not HAVING

  4. Avoid unnecessary DISTINCT: COUNT(DISTINCT) is expensive

  5. Consider materialized views: For frequently aggregated queries

Best Practices

  1. Handle NULLs explicitly: Use COALESCE if needed

  2. Use meaningful aliases: Name aggregates clearly

  3. Validate results: Check for division by zero

  4. Document calculations: Explain complex aggregations

  5. Test with edge cases: Empty groups, all NULLs

  6. Use appropriate precision: ROUND results when needed

Interested to Learn More?
Try Out the Free 14-Days Trial

More Articles

decorative icon

Experience Analytics for the AI-Era

Start your 14-day trial today - it's free and no credit card needed

decorative icon

Experience Analytics for the AI-Era

Start your 14-day trial today - it's free and no credit card needed

decorative icon

Experience Analytics for the AI-Era

Start your 14-day trial today - it's free and no credit card needed

Copyright © 2026 Paradime Labs, Inc.

Made with ❤️ in San Francisco ・ London

*dbt® and dbt Core® are federally registered trademarks of dbt Labs, Inc. in the United States and various jurisdictions around the world. Paradime is not a partner of dbt Labs. All rights therein are reserved to dbt Labs. Paradime is not a product or service of or endorsed by dbt Labs, Inc.

Copyright © 2026 Paradime Labs, Inc.

Made with ❤️ in San Francisco ・ London

*dbt® and dbt Core® are federally registered trademarks of dbt Labs, Inc. in the United States and various jurisdictions around the world. Paradime is not a partner of dbt Labs. All rights therein are reserved to dbt Labs. Paradime is not a product or service of or endorsed by dbt Labs, Inc.

Copyright © 2026 Paradime Labs, Inc.

Made with ❤️ in San Francisco ・ London

*dbt® and dbt Core® are federally registered trademarks of dbt Labs, Inc. in the United States and various jurisdictions around the world. Paradime is not a partner of dbt Labs. All rights therein are reserved to dbt Labs. Paradime is not a product or service of or endorsed by dbt Labs, Inc.