2017-05-30 91 views
0

我有一種情況,我想創建一個通過id關聯其他表中的記錄的表。關聯的一個約束是,每年在關聯的記錄中年份必須相同......有沒有辦法讓PostgreSQL在這個條件下的INSERTPostgreSQL CHECK對外鍵列以外的約束條件

表1:

CREATE TABLE "tenant"."report" (
    "id" UUID NOT NULL DEFAULT "pascal".uuid_generate_v1(), 
    CONSTRAINT "report_pkc_id" PRIMARY KEY ("id"), 

    "reporting_period" integer NOT NULL, 
    "name" VARCHAR(64) NOT NULL, 
    CONSTRAINT "report_uc__name" UNIQUE ("reporting_period", "name"), 

    "description" VARCHAR(2048) NOT NULL 
); 

表2:

CREATE TABLE "tenant"."upload_file" (
    "id" UUID NOT NULL DEFAULT "pascal".uuid_generate_v1(), 
    CONSTRAINT "upload_file_pkc_id" PRIMARY KEY ("id"), 

    "file_name" VARCHAR(256) NOT NULL, 

    "reporting_period" integer 
) 

關聯表:

CREATE TABLE "tenant"."report_upload_files" 
(
    "report_id" UUID NOT NULL, 
    CONSTRAINT "report_upload_files_pkc_tenant_id" PRIMARY KEY ("report_id"), 
    CONSTRAINT "report_upload_files_fkc_tenant_id" FOREIGN KEY ("report_id") 
    REFERENCES "tenant"."report" ("id") MATCH SIMPLE 
    ON UPDATE CASCADE ON DELETE CASCADE, 

    "upload_file_id" UUID NOT NULL, 
    CONSTRAINT "report_upload_files_fkc_layout_id" FOREIGN KEY ("upload_file_id") 
    REFERENCES "tenant"."upload_file" ("id") MATCH SIMPLE 
    ON UPDATE CASCADE ON DELETE CASCADE 
) 

我要像添加一些關聯表CREATE聲明:

CHECK ("tenant"."report"."reporting_period" = "tenant"."upload_file"."reporting_period") 
+0

https://stackoverflow.com/questions/27107034/constraint-to-check-values-from-a-remotely-related-table-via-join-etc – Neoheurist

+0

https://dba.stackexchange.com/questions/91597/check-key-if-exists-in-other-table-without-fk-constraint – Neoheurist

回答

1

使用TRIGGER功能,我能夠達到預期的效果:

CREATE FUNCTION "tenant".report_upload_files_create() RETURNS TRIGGER AS 
$report_upload_files_create$ 
    BEGIN 
    IF NOT EXISTS (
     SELECT 
     * 
     FROM 
     "tenant"."report", 
     "tenant"."upload_file" 
     WHERE 
     "tenant"."report"."id" = NEW."report_id" 
     AND 
     "tenant"."upload_file"."id" = NEW."upload_file_id" 
     AND 
     "tenant"."report"."reporting_period" = "tenant"."upload_file"."reporting_period" 
    ) 
    THEN 
     RAISE EXCEPTION 'Report and Upload File reporting periods do not match'; 
    END IF; 

    RETURN NEW; 
    END 

$report_upload_files_create$ LANGUAGE plpgsql; 

CREATE TRIGGER "report_upload_files_create" BEFORE INSERT ON "tenant"."report_upload_files" 
    FOR EACH ROW EXECUTE PROCEDURE "tenant".report_upload_files_create(); 
+0

什麼也沒有返回,所以沒有插入表中。 https://www.postgresql.org/docs/current/static/plpgsql-trigger.html – JGH

+1

隨着返回語句的添加,它現在是一個有效的答案 – JGH

2

你解決了,你自己創建的問題。

您的數據模型是典型的一對多關係。你不需要關聯表。另外,您不需要兩個相關表中的相同列,其中一個是多餘的。使用如下所示的模型以避免lack of normalization產生的典型問題。

create table tenant.report (
    id uuid primary key default pascal.uuid_generate_v1(), 
    reporting_period integer not null, 
    name varchar(64) not null, 
    description varchar(2048) not null, 
    unique (reporting_period, name) 
); 

create table tenant.upload_file (
    id uuid primary key default pascal.uuid_generate_v1(), 
    report_id uuid references tenant.report(id), 
    file_name varchar(256) not null 
); 

使用此方法不需要確保報告期間在相關記錄之間匹配。

順便說一句,我會用text而不是varchar(n)integer (serial)而不是uuid

+0

這種方法極大地改變了我的數據模型的意圖 - 因爲上傳文件可以合法地不與任何報告相關 - 例如我仍然需要知道上傳文件的報告期限,而不管它可能(也可能不會)關聯的任何報告。 – Neoheurist

+1

在規範化模型中,與報告關聯的文件和不關聯的文件是不同的數據集,應存儲在單獨的表中。作爲替代方案,您可以向報告中添加虛擬條目(一年爲一年),以使兩個表格完全相關。 (順便說一句,downvote不是我的)。 – klin

+0

@Neoheurist:如果上傳的文件沒有與報告相關聯,那麼只需在'report_id'列中存儲'null'。 –