PostgreSQL查询约束中允许的值列表?

时间:2016-01-27 00:57:15

标签: sql database postgresql database-design check-constraints

给定一个名为func returnFullName (name: (firstName: String, middleName: String?, lastName: String)) -> String? { return ("\(name.firstName) \(name.middleName) \(name.lastName)") } var fullName = returnFullName(("Matthew", middleName: "Matt", lastName: "Stevenson")) if let printFullName = fullName { print (printFullName) } 的PostgreSQL表,其中包含一个名为requests的列和一个这样的约束:

status

ALTER TABLE requests ADD CONSTRAINT allowed_status_types CHECK (status IN ( 'pending', -- request has not been attempted 'success', -- request succeeded 'failure' -- request failed )); 我可以像这样提取有关此约束的信息:

psql

但是有可能编写一个专门返回挂起,成功,失败的example-database=# \d requests Table "public.example-database" Column | Type | Modifiers ----------------------+-----------------------------+------------------------------------------------------------------- id | integer | not null default nextval('requests_id_seq'::regclass) status | character varying | not null default 'pending'::character varying created_at | timestamp without time zone | not null updated_at | timestamp without time zone | not null Indexes: "requests_pkey" PRIMARY KEY, btree (id) Check constraints: "allowed_status_types" CHECK (status::text = ANY (ARRAY['pending'::character varying, 'success'::character varying, 'failure'::character varying]::text[])) 的查询吗?

能够在我的应用程序中记住此查询的结果,而不是必须维护副本,这将是很棒的。

3 个答案:

答案 0 :(得分:3)

您可以查询系统目录pg_constraint,例如:

select consrc
from pg_constraint
where conrelid = 'requests'::regclass
and consrc like '(status%';

                                  consrc                                   
---------------------------------------------------------------------------
 (status = ANY (ARRAY['pending'::text, 'success'::text, 'failure'::text]))
(1 row) 

使用以下函数解压缩字符串:

create or replace function get_check_values(str text)
returns setof text language plpgsql as $$
begin
    return query
        execute format (
            'select * from unnest(%s)',
            regexp_replace(str, '.*(ARRAY\[.*\]).*', '\1'));
end $$;

select get_check_values(consrc)
from pg_constraint
where conrelid = 'requests'::regclass
and consrc like '(status%';

 get_check_values 
------------------
 pending
 success
 failure
(3 rows)    

答案 1 :(得分:1)

以您的设计为基础

为简化起见,我会将允许值设为(100%等效)数组文字而不是IN表达式(转换为笨拙的ARRAY构造函数):

ALTER TABLE requests ADD CONSTRAINT allowed_status_types
  CHECK (status = ANY ('{pending, success, failure}'::text[]));

系统列pg_constraint.consrc中的结果文本:

((status)::text = ANY ('{pending,success,failure}'::text[]))

现在用substring()

提取花括号之间的列表很简单
SELECT substring(consrc from '{(.*)}') AS allowed_status_types
FROM   pg_catalog.pg_constraint
WHERE  conrelid = 'public.requests'::regclass  -- schema qualify table name!
AND    conname = 'allowed_status_types';  -- we *know* the constraint name

结果:

  allowed_status_types
-------------------------
 pending,success,failure

替代设计

我真正要做的是再规范化一步:

CREATE TABLE request_status (
  status_id "char" PRIMARY KEY
, status text UNIQUE NOT NULL
, note text
);

INSERT INTO request_status(status_id, status, note) VALUES
  ('p', 'pending', 'request has not been attempted')
, ('s', 'success', 'request succeeded')
, ('f', 'failure', 'req');

CREATE TABLE requests (
  id         serial PRIMARY KEY
, status_id "char" NOT NULL DEFAULT 'p' REFERENCES request_status
, created_at timestamp NOT NULL
, updated_at timestamp NOT NULL
);

data type "char"是一个单字节ASCII字符,非常适合廉价枚举少数几个值。

您的行的大小现在是48而不是56个字节。 Details here.
检查允许的状态是微不足道的:

SELECT status FROM request_status

答案 2 :(得分:0)

您可以创建新表status_types并将表status的列request迁移为表status_types的ForeignKey。

通过这种方式,您可以进行常规的完整性检查 - 它是一种可移植的解决方案,适用于其他关系数据库。

通过这种方式,可以轻松编写专门返回允许值的查询。

扩展允许的状态类型列表非常容易。