HiveBrain v1.2.0
Get Started
← Back to all entries
snippetsqlModerate

How to specify not null contraints for the fields of composite types in postgres

Submitted by: @import:stackexchange-dba··
0
Viewed 0 times
typesthecontraintspostgresspecifynullfieldsforcompositehow

Problem

Let's say I would like to have a composite type for address, like:
create type address as (
city text,
address_line text,
zip_code int
);


And to make data integrity better, I don't want to allow NULLs to be members of city, address_line, or zip_code. So I would like to have a not null constraint for those fields.

Creating domain checks isn't working for me. So this code produces error:
create domain address_domain as address
check (
value.city is not null and
value.address_line is not null and
value.zip_code is not null
);


You might say: "Well, why won't you store address as three columns, and add contraints to the fields?". And I will answer with that I would like to have ability to make address itself nullable, but if address is present, all of it's fields should be present as well. Something like this:
create table companies (
id serial primary key,
name text not null,
headquaters address -- this one can be null tho
)

Solution

The correct syntax for a check constraint for a composite type would look like this:

create domain address_domain as address 
check (
  (value).city is not null and 
  (value).address_line is not null and
  (value).zip_code is not null
);


Let's check:

melkij=> create table test_address_domain (a address_domain);
CREATE TABLE
melkij=> insert into test_address_domain values (('foo', 'bar', 11));
INSERT 0 1
melkij=> insert into test_address_domain values (('foo', 'bar', null)); -- fails
ERROR:  value for domain address_domain violates check constraint "address_domain_check"
melkij=> insert into test_address_domain values (('foo', null, 11)); -- fails
ERROR:  value for domain address_domain violates check constraint "address_domain_check"
melkij=> insert into test_address_domain values ((null, 'bar', 11)); -- fails
ERROR:  value for domain address_domain violates check constraint "address_domain_check"
melkij=> insert into test_address_domain values (null); -- fails
ERROR:  value for domain address_domain violates check constraint "address_domain_check"


But pay attention to the last line. It seems that this is not what you want. Try allow explicitly:

melkij=*> create domain address_domain2 as address 
check (
  value is null or (
  (value).city is not null and 
  (value).address_line is not null and
  (value).zip_code is not null
));
CREATE DOMAIN
melkij=*> create table test_address_domain2 (a address_domain2);
CREATE TABLE
melkij=*> insert into test_address_domain2 values (null); -- works now
INSERT 0 1

Code Snippets

create domain address_domain as address 
check (
  (value).city is not null and 
  (value).address_line is not null and
  (value).zip_code is not null
);
melkij=> create table test_address_domain (a address_domain);
CREATE TABLE
melkij=> insert into test_address_domain values (('foo', 'bar', 11));
INSERT 0 1
melkij=> insert into test_address_domain values (('foo', 'bar', null)); -- fails
ERROR:  value for domain address_domain violates check constraint "address_domain_check"
melkij=> insert into test_address_domain values (('foo', null, 11)); -- fails
ERROR:  value for domain address_domain violates check constraint "address_domain_check"
melkij=> insert into test_address_domain values ((null, 'bar', 11)); -- fails
ERROR:  value for domain address_domain violates check constraint "address_domain_check"
melkij=> insert into test_address_domain values (null); -- fails
ERROR:  value for domain address_domain violates check constraint "address_domain_check"
melkij=*> create domain address_domain2 as address 
check (
  value is null or (
  (value).city is not null and 
  (value).address_line is not null and
  (value).zip_code is not null
));
CREATE DOMAIN
melkij=*> create table test_address_domain2 (a address_domain2);
CREATE TABLE
melkij=*> insert into test_address_domain2 values (null); -- works now
INSERT 0 1

Context

StackExchange Database Administrators Q#289205, answer score: 13

Revisions (0)

No revisions yet.