PostgreSQL 查询约束中的允许值列表?
PostgreSQL query for a list of allowed values in a constraint?
给定一个名为 requests
的 PostgreSQL table,其中包含一个名为 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[]))
但是是否可以编写一个查询,专门 returns 未决、成功、失败的 allowed_status_types
?
如果能够在我的应用程序中记住此查询的结果,而不是必须维护副本,那就太好了。
您可以查询系统目录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\[.*\]).*', ''));
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)
以您的设计为基础
为了简化事情,我将提供允许的值作为(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"
是单个 one-byte ASCII 字符,非常适合对少数可能值进行廉价枚举。
您的行的大小现在是 48 个字节,而不是 56 个字节。 Details here.
检查允许的状态很简单:
SELECT status FROM request_status
您可以创建一个新的 table status_types
并将 table request
的列 status
迁移为 table 的外键] status_types
.
这样您就可以进行通常的完整性检查 - 这是一个 portable 解决方案,适用于其他关系数据库。
这样可以轻松编写专门 returns 允许值的查询。
并且很容易扩展允许的状态类型列表。
给定一个名为 requests
的 PostgreSQL table,其中包含一个名为 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[]))
但是是否可以编写一个查询,专门 returns 未决、成功、失败的 allowed_status_types
?
如果能够在我的应用程序中记住此查询的结果,而不是必须维护副本,那就太好了。
您可以查询系统目录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\[.*\]).*', ''));
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)
以您的设计为基础
为了简化事情,我将提供允许的值作为(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"
是单个 one-byte ASCII 字符,非常适合对少数可能值进行廉价枚举。
您的行的大小现在是 48 个字节,而不是 56 个字节。 Details here.
检查允许的状态很简单:
SELECT status FROM request_status
您可以创建一个新的 table status_types
并将 table request
的列 status
迁移为 table 的外键] status_types
.
这样您就可以进行通常的完整性检查 - 这是一个 portable 解决方案,适用于其他关系数据库。
这样可以轻松编写专门 returns 允许值的查询。
并且很容易扩展允许的状态类型列表。