PostgreSQL Range Data Type
This article introduces what is PostgreSQL range data type and how to use PostgreSQL range data type.
Introduction to PostgreSQL Range Types
In PostgreSQL, Range is a data type that represents an interval of values of some element type. For example, a range of integers can represent a range of ages of a group of people, and a range of times can represent a time period for which a conference room is reserved.
The range value is an interval value, respresent by [, ], (, 和 ):
- The [indicates the start of the range, including the starting value.
- The ]indicates the end of the range, including the end value.
- The (indicates the start of the range, excluding the starting value.
- The )indicates the end of the range, excluding the end value.
Here are some examples of ranges:
- [a,b]- Including values between- aand- b, including- aand- b.
- (a,b)- Including values between- aand- b, excluding- aand- b.
- [a,b)- Including values between- aand- b, including- a, excluding- b.
- (a,b]- Including values between- aand- b, excluding- a, including- b.
- [a,)- Including- aand values greater than- a.
- (a,)- Including values greater than- a.
- (,b]- Including- band values less than- b.
- (,b)- Including values less than- b.
PostgreSQL 14 introduced the Multirange type, which is a collection of Range types. The representation method is: { range_1, range_2, ...}.
Each Range type has its corresponding Multirange type.
PostgreSQL built-in Range Types
The following table shows the range types built into PostgreSQL:
| Range | Subtype | Multirange | 
|---|---|---|
| int4range | integer | int4multirange | 
| int8range | bigint | int8multirange | 
| numrange | numeric | nummultirange | 
| tsrange | timestamp without time zone | tsmultirange | 
| tstzrange | timestamp with time zone | tstzmultirange | 
| daterange | date | datemultirange | 
PostgreSQL Range Operators and Functions
The following table shows some PostgreSQL operators for range types:
| Operator | Description | 
|---|---|
| @> | Check if the first operand (range) contains the second operand (range or element) | 
| <@ | Check if the second operand (range) contains the first operand (range or element) | 
| && | Check if two ranges have overlapping parts | 
| << | Check if the first range is on the left of the second range | 
| >> | Check if the first range is on the right of the second range | 
| &< | Check if the first range extends to the right of the second range | 
| &> | Check if the first range extends to the left of the second range | 
| -| - | Check if two ranges are adjacent | 
| + | Computes the union of two ranges | 
| * | Calculate the intersection of two ranges | 
| - | Calculate the difference of two ranges | 
These operands are also suitable for Multirange type values.
At the same time, PostgreSQL provides many useful functions for Range and Multirange data types, as follows:
- The isempty()function checks whether a given range of values is empty.
- The lower_inc()function checks whether the lower bound of a given range is inclusive.
- The lower_inf()function checks whether the lower bound of a given range is infinite.
- The lower()function returns the lower limit of a given range or range of multiple values.
- The multirange()function returns a multivalued range containing the given range.
- The range_merge()function computes the smallest range that includes all ranges or the entire multivalued range.
- The unnest()function expands a multivalued range value into a collection of range values.
- The upper_inc()function checks whether the upper limit of a given range is inclusive.
- The upper_inf()function checks whether the upper limit of a given range is infinite.
- The upper()function returns the upper bound of a given range or a range of multiple values.
PostgreSQL Range Examples
Below are some examples of PostgreSQL Range and Multirange.
To check if a range contains another range, use the following statement:
SELECT '[1,9]'::int4range @> '[3,9]'::int4range;
 ?column?
----------
 tTo check if a range contains a value, use the following statement:
SELECT '[1,9]'::int4range @> 3;
 ?column?
----------
 tTo check if a Multirange contains a range , use the following statement:
SELECT '{[1,5], [7, 9]}'::int4multirange @> '[3,4]'::int4range;
 ?column?
----------
 tCreate Your Own Range
In addition to using PostgreSQL’s built-in range types, you can create your own range types using the CREATE TYPE statement.
Here is the syntax for creating a custom range type:
CREATE TYPE name AS RANGE (
    SUBTYPE = subtype
    [, SUBTYPE_OPCLASS = subtype_operator_class ]
    [, COLLATION = collation ]
    [, CANONICAL = canonical_function ]
    [, SUBTYPE_DIFF = subtype_diff_function ]
    [, MULTIRANGE_TYPE_NAME = multirange_type_name ]
)
Assuming that you want to create a range type of time (time) named my_time_range, use the following statement:
CREATE TYPE my_time_range AS RANGE (
    SUBTYPE = time
);
The following statement uses the range type my_time_range just created:
SELECT my_time_range('10:00:00','12:00:00') @> '11:00:00'::time;
 ?column?
----------
 tConclusion
In PostgreSQL, Range is a data type that represents an interval of values of some type. The Multirange type is a collection of Range types.