2017-11-15 105 views
5

Đôi khi, trong khi tải dữ liệu hàng loạt, nó được khuyến nghị cho các ràng buộc tạm thời và các chỉ mục trên bảng. Nhưng khi tôi làm điều này, tôi phải đối mặt với một số vấn đề với sự phụ thuộc. ví dụ đơn giản của tôi:Làm thế nào có thể xem phụ thuộc vào ràng buộc khóa chính trong postgres

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; 

kịch bản của tôi:

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; 

Khi tôi chạy nó tôi nhận được lỗi:

ERROR: cannot drop constraint pk_t_place_type on table t_place_type because other objects depend on it DETAIL: view v_place depends on constraint pk_t_place_type on table t_place_type

Đó là xa lạ với tôi rằng quan điểm can phụ thuộc vào một số hạn chế. AFAIK postgres không cache kế hoạch thực hiện cho một khung nhìn.

Khi tôi thay đổi quan điểm của tôi theo cách này:

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; 

phụ thuộc đã biến mất và kịch bản của tôi thực hiện thành công.

Vì vậy, câu hỏi của tôi là: Lý do cho sự phụ thuộc này giữa chế độ xem và hạn chế là gì.

EDIT

đây https://www.postgresql.org/docs/9.5/static/sql-select.html#SQL-GROUPBY postgres tài liệu nói:

When GROUP BY is present, or any aggregate functions are present, it is not valid for the SELECT list expressions to refer to ungrouped columns except within aggregate functions or when the ungrouped column is functionally dependent on the grouped columns, since there would otherwise be more than one possible value to return for an ungrouped column. A functional dependency exists if the grouped columns (or a subset thereof) are the primary key of the table containing the ungrouped column.

Đây có phải là một lý do cho hành vi như vậy? Mặc dù tôi không có các cột không được nhóm trong chế độ xem của tôi?

Trả lời

1

Truy vấn của bạn từ chế độ xem sẽ không hoạt động nếu bạn thả PK trên public.t_place_type.

Nó sẽ tạo ra lỗi này:

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 
      ^

Đó là bởi vì, từ trích dẫn tài liệu của bạn, A functional dependency exists if the grouped columns (or a subset thereof) are the primary key of the table containing the ungrouped column.

Postgres biết rằng PK đại diện cho hàng duy nhất, vì vậy khi bạn nhóm theo hàng, bạn cũng có thể nhóm theo tất cả các cột từ bảng đó và nhận được kết quả tương tự.

Những cung cấp cho các kết quả tương tự, với là hàng ungrouped:

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; 

Và bạn đang sử dụng phụ thuộc này khi lựa chọn pt.c_name AS c_place_type, bởi vì bạn nhóm lại rằng bảng bằng chính chìa khóa pt.id, với là tồn tại PK không một khi bạn thả nó, do đó, nhóm theo nó làm cho pt.c_name cả hai không được sử dụng trong tổng hợp và không được sử dụng trong group by. Và đó là lý do tại sao Postgres phàn nàn về việc xem phụ thuộc - truy vấn của nó sẽ không hoạt động nữa khi bạn thả PK này.

Bạn có thể thử nó cho mình với ví dụ sửa đổi từ câu hỏi của bạn:

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 
      ^
*/ 
+0

Vâng, bạn hoàn toàn đúng. Lỗi của tôi. Nếu tôi sửa đổi GROUP BY như thế này: GROUP BY p.id, p.c_name, pt.c_name để tránh các cột không được nhóm lại, mọi thứ đều hoạt động tốt. Cảm ơn bạn! –

Các vấn đề liên quan