Iva*_*ila 5 postgresql constraints sql-view postgresql-9.5
有时,在批量数据加载时,建议临时删除表上的约束和索引.但是当我这样做时,我遇到了一些依赖问题.我的简化示例:
CREATE TABLE public.t_place_type
(
id serial NOT NULL,
c_name character varying(100),
CONSTRAINT pk_t_place_type PRIMARY KEY (id)
);
CREATE TABLE public.t_place
(
id serial NOT NULL,
c_name character varying(50),
id_place_type integer,
CONSTRAINT pk_t_place PRIMARY KEY (id),
CONSTRAINT fk_t_place_t_place_type FOREIGN KEY (id_place_type)
REFERENCES public.t_place_type (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
CREATE OR REPLACE VIEW public.v_place AS
SELECT p.id,
p.c_name,
pt.c_name AS c_place_type
FROM t_place p
LEFT JOIN t_place_type pt ON pt.id = p.id_place_type
GROUP BY p.id, pt.id, p.c_name;
Run Code Online (Sandbox Code Playgroud)
我的剧本:
ALTER TABLE public.t_place DROP CONSTRAINT fk_t_place_t_place_type;
ALTER TABLE public.t_place DROP CONSTRAINT pk_t_place;
ALTER TABLE public.t_place_type DROP CONSTRAINT pk_t_place_type;
Run Code Online (Sandbox Code Playgroud)
当我运行它时,我收到错误:
错误:不能在表t_place_type上删除约束pk_t_place_type,因为其他对象依赖于它DETAIL:view v_place依赖于表t_place_type上的约束pk_t_place_type
我很奇怪,视图可以取决于某些约束.AFAIK postgres不会缓存视图的执行计划.
当我以这种方式改变我的观点时:
CREATE OR REPLACE VIEW public.v_place AS
SELECT p.id,
p.c_name AS c_name,
pt.c_name AS c_place_type
FROM t_place p
LEFT JOIN t_place_type pt ON pt.id = p.id_place_type;
Run Code Online (Sandbox Code Playgroud)
依赖关系消失了,我的脚本成功执行了.
所以我的问题是:视图和约束之间存在这种依赖关系的原因是什么.
编辑
这里https://www.postgresql.org/docs/9.5/static/sql-select.html#SQL-GROUPBY postgres docs说:
当存在GROUP BY或存在任何聚合函数时,SELECT列表表达式无法引用未聚合的列,但聚合函数内或未分组的列在功能上依赖于分组列,因为否则会有更多比未归属列返回的一个可能值.如果分组列(或其子集)是包含未分组列的表的主键,则存在功能依赖性.
这是这种行为的原因吗?即使我的观点中没有未分组的列?
如果您将 PK 放在 上,您从视图中的查询将不起作用public.t_place_type。
它会产生这个错误:
ERROR: column "pt.c_name" must appear in the GROUP BY clause or be used in an aggregate function
LINE 3: pt.c_name AS c_place_type
^
Run Code Online (Sandbox Code Playgroud)
这是因为,从您的文档引用来看,A functional dependency exists if the grouped columns (or a subset thereof) are the primary key of the table containing the ungrouped column.
Postgres 知道 PK 代表唯一的行,因此一旦您按它分组,您也可以按该表中的所有列进行分组并获得相同的结果。
这些给出相同的结果,但行未分组:
SELECT * FROM public.t_place;
SELECT * FROM public.t_place GROUP BY id;
SELECT * FROM public.t_place GROUP BY id, c_name;
SELECT * FROM public.t_place GROUP BY id, c_name, id_place_type;
SELECT * FROM public.t_place GROUP BY id, id_place_type;
Run Code Online (Sandbox Code Playgroud)
并且您在选择时使用此依赖项pt.c_name AS c_place_type,因为您按主键对该表进行了分组pt.id,一旦删除它,则 PK 不存在,因此按它分组使得pt.c_name两者都不会在聚合中使用,也不会在 中使用group by。这就是 Postgres 抱怨视图依赖性的原因 - 一旦你删除这个 PK,它的查询将不再起作用。
您可以使用问题中的修改示例自行尝试:
CREATE TABLE public.t_place_type
(
id serial NOT NULL,
c_name character varying(100)
);
CREATE TABLE public.t_place
(
id serial NOT NULL,
c_name character varying(50),
id_place_type integer,
CONSTRAINT pk_t_place PRIMARY KEY (id)
);
SELECT p.id,
p.c_name,
pt.c_name AS c_place_type
FROM t_place p
LEFT JOIN t_place_type pt ON pt.id = p.id_place_type
GROUP BY p.id, pt.id, p.c_name;
/* RESULT:
ERROR: column "pt.c_name" must appear in the GROUP BY clause or be used in an aggregate function
LINE 3: pt.c_name AS c_place_type
^
*/
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
597 次 |
| 最近记录: |