【问题标题】:Postgresql: How can I verify a constraint after several update queries? [duplicate]Postgresql:如何在多次更新查询后验证约束? [复制]
【发布时间】:2024-01-17 21:30:02
【问题描述】:

我正在用 postgresql 构建一个数据库。

我有 3 个表通过多对多关系链接在一起。连接表uiComponent_cat_subcat 定义了一个具有subcategoryIdcategoryIdposition 的唯一约束(图片上的红色)。

在我的工作流程中,我必须连续更新 2 个查询。第一个打破了约束,而第二个将其重新设置。

我希望在 2 个查询之后验证此约束。

ALTER TABLE "uiComponent_cat_subcat" ALTER CONSTRAINT "unique_constraint_categoryId_subcategoryId_position" DEFERRABLE INITIALLY DEFERRED;

我尝试在约束上使用DEFERRABLE 属性并将我的查询包装在一个事务中。但是,这只能应用于设置为外键的约束。

进行两次更新查询后如何验证唯一性约束?

编辑:以下是对象定义:

1 - 创建表

CREATE TABLE IF NOT EXISTS "uiComponent" 
(
  "id"           uuid NOT NULL,
  "name"         varchar(255),
  "preview"      json,
  "symbolID"     varchar(255),
  "libraryID"    varchar(255),
  "type"         "public"."enum_uiComponent_type" DEFAULT 'basic',
  "content"      json,
  "created_at"   timestamp WITH time ZONE NOT NULL DEFAULT now(),
  "updated_at"   timestamp WITH time ZONE NOT NULL DEFAULT now(),
  PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "category" 
(
  "id"            uuid NOT NULL,
  "name"          varchar(255),
  "immuable"      boolean,
  "description"   varchar(255),
  "section"       "public"."enum_category_section" NOT NULL DEFAULT 'Components',
  "created_at"    timestamp WITH time ZONE NOT NULL DEFAULT now(),
  "updated_at"    timestamp WITH time ZONE NOT NULL DEFAULT now(),
  PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "subcategory" 
(
  "id"           uuid NOT NULL,
  "name"         varchar(255),
  "position"     integer NOT NULL,
  "created_at"   timestamp WITH time ZONE NOT NULL DEFAULT now(),
  "updated_at"   timestamp WITH time ZONE NOT NULL DEFAULT now(),
  PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "uiComponent_cat_subcat" 
(
  "id"              uuid,
  "uiComponentId"   uuid NOT NULL REFERENCES "uiComponent" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
  "categoryId"      uuid NOT NULL REFERENCES "category" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
  "subcategoryId"   uuid REFERENCES "subcategory" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
  "position"        integer NOT NULL,
  PRIMARY KEY ("id")
);

2 - 创建约束

ALTER TABLE "uiComponent_cat_subcat" 
   ADD CONSTRAINT "unique_constraint_categoryId_subcategoryId_position" UNIQUE ("categoryId", "subcategoryId", "position") 
   DEFERRABLE INITIALLY DEFERRED;

3 - 更新查询

START TRANSACTION;

UPDATE "uiComponent_cat_subcat" 
  SET "position"="position"+ 1 
WHERE "position" BETWEEN 1 AND 1 
AND "categoryId" = '10e4621e-f52d-4fe2-a408-139841718fd5' 
AND "subcategoryId" = 'a7770326-35be-45ae-ba26-4635cfb6f4dc';

UPDATE "uiComponent_cat_subcat" 
  SET "position"=1 
WHERE "id" = '50022f87-8fe9-4f21-a622-d5f51c16d9fc'

COMMIT;

问题解决了,但是不知道为什么??? 在事务中包装查询是否允许我在提交后检查约束。

【问题讨论】:

  • 我没有看到问题。使用延迟外键,您可以在更改其他表后更新uiComponent_cat_subcat 。只是不要使用级联更新。此外,如果您正在更新主键,那么您做错了什么。但最好通过显示要运行的 SQL 语句和表定义来更详细地解释。
  • 为什么componentId不在uiComponent_cat_subcat的PK中?并且类别似乎在功能上依赖于子类别(并且位置是多余的,但可能是另一个候选键的一部分)
  • @LaurenzAlbe 谢谢。如何在同一查询中增加多行并更新一行? PS:我写了所有的查询来回答这个问题????
  • @joop 一个组件可以在几对类别/子类别中,并且在每对中也有不同的位置。另外,“为什么componentId不在uiComponent_cat_subcat的PK中”是什么意思? uiComponent_cat_subcat 可以有多个uiComponentId

标签: postgresql sql-update unique-constraint


【解决方案1】:

1 - 创建表

CREATE TABLE IF NOT EXISTS "uiComponent" 
(
  "id"           uuid NOT NULL,
  "name"         varchar(255),
  "preview"      json,
  "symbolID"     varchar(255),
  "libraryID"    varchar(255),
  "type"         "public"."enum_uiComponent_type" DEFAULT 'basic',
  "content"      json,
  "created_at"   timestamp WITH time ZONE NOT NULL DEFAULT now(),
  "updated_at"   timestamp WITH time ZONE NOT NULL DEFAULT now(),
  PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "category" 
(
  "id"            uuid NOT NULL,
  "name"          varchar(255),
  "immuable"      boolean,
  "description"   varchar(255),
  "section"       "public"."enum_category_section" NOT NULL DEFAULT 'Components',
  "created_at"    timestamp WITH time ZONE NOT NULL DEFAULT now(),
  "updated_at"    timestamp WITH time ZONE NOT NULL DEFAULT now(),
  PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "subcategory" 
(
  "id"           uuid NOT NULL,
  "name"         varchar(255),
  "position"     integer NOT NULL,
  "created_at"   timestamp WITH time ZONE NOT NULL DEFAULT now(),
  "updated_at"   timestamp WITH time ZONE NOT NULL DEFAULT now(),
  PRIMARY KEY ("id")
);

CREATE TABLE IF NOT EXISTS "uiComponent_cat_subcat" 
(
  "id"              uuid,
  "uiComponentId"   uuid NOT NULL REFERENCES "uiComponent" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
  "categoryId"      uuid NOT NULL REFERENCES "category" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
  "subcategoryId"   uuid REFERENCES "subcategory" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
  "position"        integer NOT NULL,
  PRIMARY KEY ("id")
);

2 - 创建约束

ALTER TABLE "uiComponent_cat_subcat" 
   ADD CONSTRAINT "unique_constraint_categoryId_subcategoryId_position" UNIQUE ("categoryId", "subcategoryId", "position") 
   DEFERRABLE INITIALLY DEFERRED;

3 - 更新查询

START TRANSACTION;

UPDATE "uiComponent_cat_subcat" 
  SET "position"="position"+ 1 
WHERE "position" BETWEEN 1 AND 1 
AND "categoryId" = '10e4621e-f52d-4fe2-a408-139841718fd5' 
AND "subcategoryId" = 'a7770326-35be-45ae-ba26-4635cfb6f4dc';

UPDATE "uiComponent_cat_subcat" 
  SET "position"=1 
WHERE "id" = '50022f87-8fe9-4f21-a622-d5f51c16d9fc'

COMMIT;

问题解决了,但不知道为什么? 在事务中包装查询是否允许我在提交后检查约束。

【讨论】:

  • INITIALLY DEFERRED; 是它现在有效的关键原因。
  • @a_horse_with_no_name 非常感谢?