sea*_*lor 6 sql database postgresql database-design check-constraints
给定一个名为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[]))
但是是否可以编写专门返回allowed_status_types未决,成功,失败的查询?
能够在我的应用程序中记住此查询的结果,而不需要维护重复的副本,将是很棒的。
为了简化事情,我将提供允许的值作为(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
);
数据类型"char"是单个单字节 ASCII 字符,非常适合对少数可能值进行廉价枚举。
行的大小现在是 48 个字节,而不是 56 个字节。详细信息请参见此处。
检查允许的状态很简单:
SELECT status FROM request_status
您可以查询系统目录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)    
| 归档时间: | 
 | 
| 查看次数: | 3041 次 | 
| 最近记录: |