Whenever we create a table in PostgreSQL, a composite type is automatically created behind the scenes. This composite type is based on the table that we created. Each column in the table becomes a field in the composite type.
If the table already uses a composite type, then the composite type that PostgreSQL creates will include that type in its definition, thereby creating a situation where we effectively have a nested composite type.
Example
Suppose we create the following composite type:
CREATE TYPE address AS(
street text,
city varchar(200),
state varchar(50),
postcode varchar(12),
country_code char(3)
);
And we create the following table that uses that type:
CREATE TABLE person (
person_id serial primary key,
first_name varchar(100),
last_name varchar(100),
address_details address
);
Here, the address_details
column uses the address
composite type that we created.
As mentioned, whenever we create a table, PostgreSQL automatically creates a composite type. The composite type gets the same name as the table. Therefore, when we created the person
table, a composite type called person
was created.
Given the person
table already uses a composite type (for the address_details
column), the new (automatically created) person
composite type will include that composite type in its definition. Therefore, we’ll effectively have a nested composite type.
Using the Nested Composite Type
We could go ahead and create another table and assign the newly created composite type to a column:
CREATE TABLE person2 (
details person
);
Here, I created a table with one column. That column uses the person
composite type that PostgreSQL created automatically when I created the person
table in the previous example.
This isn’t without its limitations though. Probably the main limitation would be the fact that we can’t apply constraints against composite types (at least, not as of PostgreSQL 16).
Using our example, the original table had a primary key (the person_id
column). When we created the person2
table, that column is represented by a field in the person composite type, and so it is no longer a primary key for the table. Of course, we could always create a separate primary key column in the person2
table.
It’s also possible to create a domain over the composite type, and then create any constraints as CHECK
constraints of the domain.