PostgreSQL CHECK除了外键之外的列的约束

时间:2017-05-30 18:01:29

标签: sql postgresql

我有一种情况,我想创建一个表,通过id关联其他表的记录。关联的约束是每个表中关联的记录中的年份必须相同...有没有办法在CHECK上将PostgreSQL INSERT这个条件?{/ p>

表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")

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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();