简体   繁体   English

在Postgresql中的索引约束上初始可延迟

[英]DEFERRABLE INITIALLY DEFERRED on index contraint in postgresql

I can add DEFERRABLE INITIALLY DEFERRED using the following query: 我可以使用以下查询添加DEFERRABLE INITIALIALDEFERED:

ALTER TABLE user DROP CONSTRAINT unq_user_address, add CONSTRAINT unq_user_address UNIQUE(user_address) deferrable INITIALLY DEFERRED;

Now I have another column and I want to add DEFERRABLE INITIALLY DEFERRED. 现在,我还有另一列,我想添加DEFERRABLE INITIALIALLY DEFERRED。 The constraint is on index so I am getting error when I do so. 约束是在索引上的,所以我这样做时会出错。

Here is the index constraint: 这是索引约束:

CREATE UNIQUE INDEX unq_account
  ON user 
  USING btree 
  (lower(account::text) COLLATE pg_catalog."default");

I modified it to say, 我修改为说

CREATE UNIQUE INDEX unq_account
      ON user 
      USING btree 
      (lower(account::text) COLLATE pg_catalog."default") deferrable INITIALLY DEFERRED;

Also tried, 也尝试过

CREATE UNIQUE INDEX unq_account
      ON user 
      USING btree 
      (lower(account::text) COLLATE pg_catalog."default") UNIQUE_CHECK_PARTIAL;

So don't know how to apply the same on index. 因此,不知道如何在索引上应用相同的内容。

I see the following official doc: https://www.postgresql.org/docs/9.6/static/index-unique-checks.html 我看到以下官方文档: https : //www.postgresql.org/docs/9.6/static/index-unique-checks.html

UNIQUE_CHECK_PARTIAL indicates that the unique constraint is deferrable. UNIQUE_CHECK_PARTIAL表示唯一约束是可延迟的。 PostgreSQL will use this mode to insert each row's index entry. PostgreSQL将使用此模式插入每一行的索引条目。 The access method must allow duplicate entries into the index, and report any potential duplicates by returning FALSE from aminsert. 访问方法必须允许重复的条目进入索引,并通过从aminsert返回FALSE来报告任何潜在的重复。 For each row for which FALSE is returned, a deferred recheck will be scheduled. 对于返回FALSE的每一行,将安排一次延迟的重新检查。

And here: 和这里:

UNIQUE_CHECK_EXISTING indicates that this is a deferred recheck of a row that was reported as a potential uniqueness violation. UNIQUE_CHECK_EXISTING表示这是对报告为潜在唯一性违规的行的重新检查。 Although this is implemented by calling aminsert, the access method must not insert a new index entry in this case. 尽管这是通过调用aminsert来实现的,但是在这种情况下,访问方法不得插入新的索引条目。 The index entry is already present. 索引条目已经存在。 Rather, the access method must check to see if there is another live index entry. 而是,访问方法必须检查以查看是否还有另一个活动索引条目。 If so, and if the target row is also still live, report error. 如果是这样,并且目标行也仍然存在,请报告错误。

Is it something I need to use and if yes then how? 是我需要使用的东西吗?如果是,那么如何使用?

You cannot define an index as deferrable. 您不能将索引定义为可递延索引。 Deferrable is an attribute of constraints, not indexes. 可延迟性是约束的属性,而不是索引。

CREATE TABLE test_table
(
    test_col integer not null
);

ALTER TABLE test_table
ADD constraint test_col_unique unique (test_col) deferrable initially deferred;

However, you cannot use arbitrary expressions for unique constraints, only direct column references: 但是,不能将任意表达式用于唯一约束,只能使用直接列引用:

ALTER TABLE test_table
ADD CONSTRAINT test_col_abs_unique UNIQUE (abs(test_col));

will report 将报告

ERROR:  syntax error at or near "("

because the parser only handles simple column references. 因为解析器仅处理简单的列引用。

So you can't make this check deferrable. 因此,您不能将这张支票延期。

You can't use neither of UNIQUE_CHECK_PARTIAL , UNIQUE_CHECK_EXISTING in CREATE INDEX ... SQL query. 您不能在CREATE INDEX ... SQL查询中使用UNIQUE_CHECK_PARTIALUNIQUE_CHECK_EXISTING As it said on the Access Method Interface documentation page you quote, 就像您在“ 访问方法接口”文档页面上所说的那样,

...the aminsert function is passed a checkUnique parameter having one of the following values: UNIQUE_CHECK_NO..., UNIQUE_CHECK_YES..., UNIQUE_CHECK_PARTIAL..., UNIQUE_CHECK_EXISTING ...向aminsert函数传递了一个checkUnique参数,该参数具有以下值之一:UNIQUE_CHECK_NO ...,UNIQUE_CHECK_YES ...,UNIQUE_CHECK_PARTIAL ...,UNIQUE_CHECK_EXISTING

So those are values for checkUnique parameter to be passed to aminsert function (which I assume is a part of Access Method Interface API or internals) 因此,这些是要传递给aminsert函数的 checkUnique参数的值(我认为这是访问方法接口API或内部的一部分)

The rest is answered by Craig. 其余的由克雷格回答。

You can alter table "user" add CONSTRAINT unq_user_address UNIQUE(account) deferrable INITIALLY DEFERRED; 您可以alter table "user" add CONSTRAINT unq_user_address UNIQUE(account) deferrable INITIALLY DEFERRED; losing the lower(account) condition: 失去lower(account)条件:

as a workaround you can do this ugly thing - add column and trigger: 作为解决方法,您可以执行此丑陋的操作-添加列并触发:

b=# create table "user" (account text, account_uq text);
CREATE TABLE
b=# create function tf() returns trigger as $$ begin NEW.account_uq = lower(NEW.account); return NEW; end;$$ language plpgsql;
ERROR:  function "tf" already exists with same argument types
b=# CREATE TRIGGER tg BEFORE UPDATE OR INSERT ON "user" FOR EACH ROW EXECUTE PROCEDURE tf();
CREATE TRIGGER
b=# alter table "user" add CONSTRAINT another_uq UNIQUE(account_uq) deferrable INITIALLY DEFERRED;
ALTER TABLE
b=# insert into "user" (account) select 'b';
INSERT 0 1
b=# begin;
BEGIN
b=# insert into "user" (account) select 'B';
INSERT 0 1
b=# select * from "user";
 account | account_uq
---------+------------
 b       | b
 B       | b
(2 rows)

b=# end;
ERROR:  duplicate key value violates unique constraint "another_uq"
DETAIL:  Key (account_uq)=(b) already exists.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM