如何创建一个将card_id
与allowed_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}');
答案 0 :(得分:0)
card_id
首先, 如果 您需要表card_allowed
,请使用普通varchar
或text
列(包含多个条目),而不是数组:
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
而不是 ,这是标准SQL中的保留字,对实际time
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();