Skip to content
/ Chapter 20 · Statistics and Distributions
Lesson 20.2 · garden_shop
Lesson 20.2

Standard Deviation in SQL

Two groups can share an average and still look nothing alike. The standard deviation measures how far values typically sit from their average.

An average says where the values sit. It says nothing about whether they cluster tightly or scatter. Garden Shop's Tools and Pots & Planters both average $13.17, but the tools run from $8 to $22 and the pots from $6.50 to $19. The standard deviation puts a number on the scatter, in the same units as the values.

Pattern
select round(avg(price), 2) as avg_price,
       round(stddev_samp(price), 2) as price_stddev,
       round(var_samp(price), 2) as price_variance
from products

Reading the number

Garden Shop's prices average $14.36 with a standard deviation of $7.51, so a typical product sits about seven or eight dollars from the average. The variance is the standard deviation squared (56.34 here). It is in squared dollars, which is why reports quote the standard deviation instead.

Sample or population

There are two versions of each function. stddev_samp treats the rows as a sample of something larger and divides by one less than the row count. stddev_pop treats them as the whole population and divides by the row count:

The two versions side by side
select round(stddev_samp(price), 2) as sample_stddev,
       round(stddev_pop(price), 2) as population_stddev
from products

With 24 products the difference is small (7.51 against 7.35). Plain stddev() means the sample version in DuckDB and PostgreSQL. In MySQL it means the population version, so name the one you mean.

A group of one

A single value has no spread to estimate from, so the sample version returns NULL while the population version returns 0:

One product
select stddev_samp(price) as sample_stddev,
       stddev_pop(price) as population_stddev
from products
where product_id = 1

Expect those NULLs whenever you group finely enough that some groups hold one row.

Schema · Garden Shop Tables · products, categories 2 tables
Table · products

One row per product, with price, cost, and inventory levels.

9 columns · 24 rows
product_id int product_name text category_id int supplier_id int price decimal cost decimal quantity_on_hand int reorder_level int discontinued bool
Table · categories

Lookup table of product categories.

2 columns · 8 rows
category_id int category_name text
Your task

For each category, return category_name, products (the number of products), avg_price, and price_stddev (the sample standard deviation of price), both rounded to two decimals. Sort by price_stddev from highest to lowest, then by category_name.

·

Run your query to inspect the result.

Expected answer
  • Columns: category_name, products, avg_price, price_stddev.
  • Rows: all 8 categories, Houseplants first with a spread of 7.95.
  • Tools and Pots & Planters share an average of 13.17 but not a spread: 7.69 against 6.29.
  • Outdoor Decor and Soil & Compost tie at 1.76, so the category name breaks the tie.