Range, Multiranges and composite data types

The RANGE data type represents a contiguous intervals of values; it is defined by its lower and upper bound.

//It's compatible with previous postgreSQL data types
create table lista(
    id  serial primary  key,
    user_id int,
    raggio  int4range  //int8range, numrange, daterange, tsrange, tstzrange
)

insert into lista(raggio) values ('[12, 44]');
insert into lista(raggio8) values ('[12, 44]');
insert into lista(raggionum) values ('[12.12 , 44]'); //num for decimals
insert into lista(raggiodata) values ('[2021-01-12, 2021-01-15]');
insert into lista(raggiots) values ('[2021-01-12 12:12:12, 2021-01-15 15:15:15]');
insert into lista(raggiotstz)values('[2021-01-12 12:12:12+02,2021-01-15 15:15:15+02]')

By default, PostgreSQL ranges follow the [inclusive, exclusive) bounds format.

The lower() and upper() range functions retrieve their respective bounds. We can define infinite bounds using the 'infinity' string (compatible with tsrange, tstzrange, daterange, and numrange in both constructors and literals), NULL (in range constructors), or an empty bound (in range literals).

Arrays and ranges are both collections of data types, but they use different operators. Array operators like ANY or EXISTS operate on a series of values, while a range represents a single contiguous interval.

Range operations include:

The not-extend-to-the-left/right operators (&> and &<) return true depending on the starting and ending bound between two ranges.

We can process math operations using:

chevron-rightThe ranges sum (+), subtaction (-) and intersections (*) operationshashtag

The sum operator (+) returns a single range from multiple overlapping and contigous ranges.

Ranges are considered 'contiguous' based on their data type. For discrete data types, contiguity means there are no skipped units between their bounds, while continuous data types require its ranges to share the same boundary point, defined by their precision.

The subtract operation (-) returns the difference between two ranges. It returns error if the second range is contained within the first.

The intersection operator (*) returns a single range of values shared by the two input ranges.

Multirange data type syntax and operations

The multirange data type, introduced in PostgreSQL 14, allows for the representation of multiple non-contiguous ranges in a single value. It normalizes any overlapping or adjacent ranges within it and orders them by their lower bound.

We can apply range opration on multiranges:

The containment operator (@>) returns true if every value within the second element is completely contained by at least one range in the first multirange.

The addition operator (+) returns a new normalized multirange value.

The subtraction operation (-) returns a multirange containing parts of the first multirange that do not overlap with any ranges in the second.

The intersection operation (*) returns a multirange containing parts of the first multirange that do overlap with any ranges in the second.

Multirange on table column

The upper()/lower() function provides the upper/lower bound among all ranges within a multirange value.

The range_agg() function aggregates individual range values from multiple rows into a single multirange.

PostgreSQL composite custom data types

PostgreSQL data types include composite, enum, range and base.

The composite data type defines an object-like structure with multiple user-defined fields and their paired data type. Type casting during INSERT validates and adapts the data to the composite fields. If casting is not used, PostgreSQL validates each field individually and produces an error if the data does not match the field definitions.

We can SELECT a single composite value column by specifying its name within parentheses (). By default, SQL interprets dot notation (.) as extracting columns; the parentheses force SQL to evaluate the value as a composite, enabling direct access to its individual fields in your SELECT query.

We update a composite data type column by returning a new composite value that includes the appended element.

chevron-rightCollatation on composite fields and UNNEST FROM ruleshashtag

We can define the collatable sorting rules for text-based fields within the composite data type.

We use the UNNEST function to access composite values from a table's array column. It returns each array element as a row in a new set. We then alias this set of composite values and their fields.

The FROM clause specifies the data sources in a query. It automatically performs a CROSS JOIN with the rows returned by the expressions, making the data available in the SELECT.

Composite data type arguments on PostgreSQL functions

A SQL function can accept a custom data type as its argument, allowing us to access and manipulate its fields during each invocation.

A composite data type shares its structure with a table, as both are ordered collections of named attributes with assigned data types.

Every CREATE TABLE statement implicitly defines a corresponding composite data type, which serves as the row structure for the instances stored in the table. The table provides persistent storage for this data, managed by its composite row type.

We can use a table's implicit composite data type as a custom argument in SQL functions, passing specific instances of users%ROWTYPE directly from a SELECT query.

Instead of passing a query result as a SQL function argument, we can process the query within a PL/pgSQL DO block.

The declared variable data type %ROWTYPE will hold the row structure of the instances returned by the SELECT ... INTO query. It contains the implicit composite value of the table row, allowing us to directly access and manipulate its fields.

Last updated