假设我有这种自定义类型:
CREATE TYPE post AS (
title varchar(100),
content varchar(10000)
);
这张表:
CREATE TABLE blogs (
-- Constraint on one custom type element:
one_post post NOT NULL
CHECK ((one_post).title IS NOT NULL AND (one_post).content IS NOT NULL),
-- Constraint on array elements:
posts post[] NOT NULL CHECK (???)
);
如代码中所述,我想检查posts
的每个元素的标题和内容是否为NOT NULL
,但我找不到表达方式。这样做的正确方法是什么?
(P.S。:我知道正确的方法是规范化我的架构,我只是好奇我能提出的问题。)
答案 0 :(得分:3)
对于复杂的检查约束,通常使用存储的函数。
我尝试以方便的方式制作它:
首先:
create type post as (
title varchar(100),
content varchar(10000)
);
create function is_filled(post) returns bool immutable language sql as $$
select $1.title is not null and $1.content is not null
$$;
with t(x) as (values(('a','b')::post), (('a',null)::post), ((null,null)::post))
select *, is_filled(x), (x).is_filled from t;
╔═══════╤═══════════╤═══════════╗ ║ x │ is_filled │ is_filled ║ ╠═══════╪═══════════╪═══════════╣ ║ (a,b) │ t │ t ║ ║ (a,) │ f │ f ║ ║ (,) │ f │ f ║ ╚═══════╧═══════════╧═══════════╝
在这里你可以看到函数调用的两种语法(我个人喜欢第二种 - 它更像OOP)
下一步:
create function is_filled(post[]) returns bool immutable language sql as $$
select bool_and((x).is_filled) and $1 is not null from unnest($1) as x
$$;
with t(x) as (values(('a','b')::post), (('a',null)::post), ((null,null)::post))
select (array_agg(x)).is_filled from t;
╔═══════════╗ ║ is_filled ║ ╠═══════════╣ ║ f ║ ╚═══════════╝
请注意,我们可以使用具有相同名称但具有不同参数的函数 - 在PostgreSQL中可以使用。
最后:
create table blogs (
one_post post check ((one_post).is_filled),
posts post[] check ((posts).is_filled)
);
insert into blogs values(('a','b'), array[('a','b'),('c','d')]::post[]); -- Works
insert into blogs values(('a','b'), array[('a','b'),(null,'d')]::post[]); -- Fail
insert into blogs values(('a',null), array[('a','b')]::post[]); -- Fail
PS:清除我们实验的脚本:
/*
drop table if exists blogs;
drop function if exists is_filled(post);
drop function if exists is_filled(post[]);
drop type if exists post;
*/