NumbersSQL standard

WIDTH_BUCKET

Tells you which of several equal ranges a number falls into: 1, 2, 3…

Syntax

WIDTH_BUCKET(<value>, <from>, <to>, <bucket count>)
WIDTH_BUCKET(<value>, ARRAY[<bound1>, <bound2>, …])

Splits the interval from <from> to <to> into the given number of equal buckets and returns the bucket number for the value. Anything below the start gets 0, and anything not below the end gets the count + 1. Handy for histograms: how many orders are under 50, from 50 to 100 and so on.

Data for the examples

orders

idcreated_atamount
12026-07-03 10:15:00120.50
22026-07-28 18:40:0080.25
32026-08-09 09:05:00199.99
42026-08-21 14:30:0045.00
52026-09-02 11:00:0064.75

These tables already exist in the sandbox — the examples below use them. Want to try this in your own database? Copy the SQL.

The bucket number
SELECT WIDTH_BUCKET(35, 0, 100, 4) AS bucket;
bucket
2

The interval 0–100 is split into four buckets of 25, and 35 falls into the second.

A histogram of order amounts
SELECT WIDTH_BUCKET(amount, 0, 200, 4) AS bucket,
COUNT(*) AS order_count
FROM orders
GROUP BY bucket
ORDER BY bucket;
bucketorder_count
11
22
31
41

Buckets of 50: 1 — under 50, 2 — from 50 to 100 and so on.

Uneven bounds as an array
SELECT id, amount,
WIDTH_BUCKET(amount, ARRAY[50, 100, 150]) AS bucket
FROM orders;
idamountbucket
1120.502
280.251
3199.993
445.000
564.751

With an array, the bounds can be anything: under 50 — bucket 0, from 50 to 100 — 1, from 100 to 150 — 2, above that — 3.

Watch out

Values outside the interval aren't lost — they get 0 or the count + 1: WIDTH_BUCKET(250, 0, 200, 4) gives 5.

The end of the interval isn't part of the last bucket: WIDTH_BUCKET(200, 0, 200, 4) gives 5 as well, not 4.

A bucket number isn't a bound. To label a histogram, calculate the bound back: (bucket - 1) * 50.

Related functions