如何在postgres中为复合类型的字段指定非空约束

Lin*_*nk0 13 postgresql composite-types domain

假设我想要一个复合类型的地址,例如:

create type address as (
  city text,
  address_line text,
  zip_code int
);
Run Code Online (Sandbox Code Playgroud)

为了使数据完整性更好,我不想允许NULLs 成为cityaddress_line或 的成员zip_code。所以我想对not null这些字段进行限制。

创建域检查对我来说不起作用。所以这段代码会产生错误:

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
);
Run Code Online (Sandbox Code Playgroud)

您可能会说:“那么,为什么不将地址存储为三列,并向字段添加约束呢?”。我会回答说,我希望能够使地址本身可以为空,但如果地址存在,那么它的所有字段也应该存在。像这样的东西:

create table companies (
  id serial primary key,
  name text not null,
  headquaters address -- this one can be null tho
)
Run Code Online (Sandbox Code Playgroud)

Mel*_*kij 12

复合类型检查约束的正确语法如下所示:

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
);
Run Code Online (Sandbox Code Playgroud)

让我们检查:

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"
Run Code Online (Sandbox Code Playgroud)

但请注意最后一行。看来这不是你想要的。尝试明确允许:

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
Run Code Online (Sandbox Code Playgroud)

  • 是否可以在单个表达式中创建域和复合类型?看来现在你必须先“CREATE TYPE”,然后再“CREATE DOMAIN”? (2认同)