视图如何取决于postgres中的主键约束

时间:2017-11-15 07:31:39

标签: 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;

我的剧本:

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;

当我运行它时,我收到错误:

  

错误:无法在表t_place_type上删除约束pk_t_place_type   因为其他对象依赖于它   DETAIL:view v_place依赖于表上的约束pk_t_place_type   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;

依赖关系消失了,我的脚本成功执行。

所以我的问题是:视图和约束之间存在这种依赖关系的原因是什么。

修改

此处https://www.postgresql.org/docs/9.5/static/sql-select.html#SQL-GROUPBY postgres文档说:

  

当存在GROUP BY或存在任何聚合函数时,它   对SELECT列表表达式无效以引用未分组   除聚合函数内或未分组列时的列   功能上依赖于分组列,因为它会   否则为一个未分组的人返回一个以上的可能值   柱。如果分组列(或a),则存在功能依赖性   其子集)是包含该表的表的主键   未分组的专栏。

这是这种行为的原因吗?即使我在视图中没有未分组的列?

1 个答案:

答案 0 :(得分:1)

如果您在public.t_place_type上删除PK,那么您在查看中的查询将无效。

会产生此错误:

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
            ^

这是因为,从您的文档引文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;

您在选择pt.c_name AS c_place_type时使用此依赖关系,因为您按主键pt.id对该表进行了分组,一旦删除它就不存在PK,因此按其分组会{{1}两者都没有在聚合中使用而在pt.c_name中没有使用。这就是为什么Postgres抱怨视图依赖 - 一旦你放弃这个PK,它的查询将不再起作用。

您可以使用您问题中的修改示例自行尝试:

group by