更新其他列有效性的状态标志的功能?

时间:2015-07-23 13:15:55

标签: sql postgresql database-design referential-integrity check-constraints

如何创建一个将card_idallowed_cards数组元素进行比较的函数?
如果它在此数组中,则列状态必须更新为TRUE

CREATE TABLE client_1 (
  id bigint NOT NULL,
  "time" timestamp without time zone DEFAULT now(),
  status boolean,
  card_id character varying(10),
  CONSTRAINT client_1_pkey PRIMARY KEY (id)
);

CREATE TABLE allowed_cards (
  allowed_cards character varying(10)[]
);

INSERT INTO allowed_cards VALUES ('{DD3234,FF2342}');

1 个答案:

答案 0 :(得分:0)

始终执行有效card_id

首先, 如果 您需要表card_allowed,请使用普通varchartext列(包含多个条目),而不是数组:

CREATE TABLE card_allowed (
  card_id varchar(10) NOT NULL PRIMARY KEY
);

INSERT INTO card_allowed VALUES ('DD3234'), ('FF2342');

接下来,要 强制 有效卡片,您现在只需使用FK constraint

CREATE TABLE client_1 (
  client_1_id  bigint NOT NULL PRIMARY KEY,
  tstz         timestamptz DEFAULT now(),
  -- card_valid   boolean,
  card_id      varchar(10),
  CONSTRAINT client_1_card_id_fk FOREIGN KEY (card_id) REFERENCES card_allowed
);

由于该列可以为NULL,因此如果您没有有效的card_id,则可以将其留空。

您不需要额外的列(您将其命名为status,我将其重命名为card_valid)。

我还更改了一些列名以使其更有用。除其他外,我使用列名tstz而不是 time ,这是标准SQL中的保留字,对实际timestamptz也有误导性列。


如果您需要在card_id中允许无效值(真的吗?),则无法使用FK约束。还有其他选择:

仅检查新条目

你可以"假"运行检查的IMMUTABLE函数:

CREATE OR REPLACE FUNCTION f_card_allowed(text)
  RETURNS bool AS
$func$
SELECT EXISTS (SELECT 1 FROM card_allowed WHERE card_allowed = $1);
$func$
  LANGUAGE sql STABLE;  -- not actually IMMUTABLE

该函数不是真正不可变,因为它依赖于另一个表的值。所以它实际上只有STABLE。相同调用的结果可以在事务之间更改。根据定义CHECK constraints期望IMMUTABLE函数,但允许一些余地(特别是对于时间函数)STABLE是可以容忍的。您应该将CHECK约束标记为NOT VALID来记录此内容,但是:

ALTER TABLE client_1 ADD CONSTRAINT client_1_card_allowed
CHECK (f_card_allowed(card_id)) NOT VALID;

区别:未强制执行参照完整性,与FK约束一样。仅在插入/更新时检查行,并且此时必须有效。没有对现有行的状态做出承诺:您现在可能已更改card_allowed中的值。详细说明:

设置状态一次

现在您需要附加标记card_valid 我在上面的表定义中注释掉了。您有 FK约束:

UPDATE client_1 c
SET    card_valid = EXISTS (SELECT 1 FROM card_allowed WHERE card_id = c.card_id);

设置每次更改后的状态

您可以在每个插入/更新的行的触发器功能中执行相同的操作:

CREATE OR REPLACE FUNCTION trg_client_1_insupbef()
  RETURNS trigger AS
$BODY$
BEGIN
   NEW.card_valid := EXISTS (SELECT 1 FROM card_allowed WHERE card_id = NEW.card_id);
   RETURN NEW;
END
$BODY$
  LANGUAGE plpgsql;

CREATE TRIGGER insupbef
BEFORE INSERT OR UPDATE ON client_1
FOR EACH ROW EXECUTE PROCEDURE trg_client_1_insupbef();