PostgreSQL约束 - 只有一行可以设置标志

Lec*_*cko 20 sql postgresql

我有一个PostgreSQL表

CREATE TABLE my_table
(
  id serial NOT NULL,
  name text,
  actual boolean DEFAULT false,
  CONSTRAINT my_table_pkey PRIMARY KEY (id),
);
Run Code Online (Sandbox Code Playgroud)

如何设置只有一行可以actual设置标志的约束TRUE

a_h*_*ame 44

您只能为该值在该列上创建唯一索引:

create unique index on my_table (actual) 
where actual = true;
Run Code Online (Sandbox Code Playgroud)

SQLFiddle:http://sqlfiddle.com/#!15/91f62/1

  • @FrozenFlame:不,`actual = true`很好。实际上,“实际”就足够了。 (3认同)

Mic*_*lif 7

我的方法将为基于索引的解决方案添加另一个功能:在另一行上设置标志时自动停用当前标志.

那当然是一个触发因素.

我还建议,如弗兰克海肯斯所建议的,将"非实际"状态存储为null代替false.在postgresql中,每个null值都与另一个null值不同,因此unicity约束很容易解决:我们只允许一个true值,并且允许尽可能多的null值.

这是我的实现:

CREATE TABLE my_table
(
  id serial NOT NULL,
  name text,
  actual boolean,
  CONSTRAINT my_table_pkey PRIMARY KEY (id),
  CONSTRAINT actual_not_false CHECK(actual != false)
);
Run Code Online (Sandbox Code Playgroud)

.

CREATE UNIQUE INDEX ON my_table USING btree(actual nulls LAST);
Run Code Online (Sandbox Code Playgroud)

.

CREATE OR REPLACE FUNCTION ensure_only_one_enabled_state_trigger()
 RETURNS trigger
AS $function$
BEGIN
    -- nothing to do if updating the row currently enabled
    IF (TG_OP = 'UPDATE' AND OLD.actual = true) THEN
        RETURN NEW;
    END IF;

    -- disable the currently enabled row
    EXECUTE format('UPDATE %I.%I SET actual = null WHERE actual = true;', TG_TABLE_SCHEMA, TG_TABLE_NAME);

    -- enable new row
    NEW.actual := true;
    RETURN NEW;
END;
$function$
LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

.

CREATE TRIGGER my_table_only_one_enabled_state
BEFORE INSERT OR UPDATE OF actual ON my_table
FOR EACH ROW WHEN (NEW.actual = true)
EXECUTE PROCEDURE ensure_only_one_enabled_state_trigger();
Run Code Online (Sandbox Code Playgroud)


小智 5

这应该在排除约束条件下可行。对于您的情况:

CREATE TABLE my_table
(
    id serial NOT NULL,
    name text,
    actual boolean DEFAULT false,
    CONSTRAINT my_table_pkey PRIMARY KEY (id),
    EXCLUDE (actual WITH =) WHERE (actual)
);
Run Code Online (Sandbox Code Playgroud)

经过测试:

INSERT INTO my_table VALUES (1, 'something', false);
INSERT INTO my_table VALUES (2, 'something_else', true);
Run Code Online (Sandbox Code Playgroud)

那么以下是约束违规

INSERT INTO my_table VALUES (3, 'third_thing', true);
Run Code Online (Sandbox Code Playgroud)