gpt4 book ai didi

postgresql - 约束,基于与另一个表的连接

转载 作者:行者123 更新时间:2023-12-05 02:18:42 27 4
gpt4 key购买 nike

我有表 tariffs,有两列:(tariff_id, reception)

我有表 users,有两列:(user_id, reception)

我的表 users_tariffs 有两列:(user_id, tariff_id)

我想防止将一个接收的资费分配给另一个接收的用户的情况。我该怎么做?

E.G

用户:

user_id | reception
Putin | Russia
Trump | USA

关税:

tariff_id | reception
cheap | USA
expensive | Russia

users_tariffs 的错误情况,因为 Cheap tariff 仅适用于美国:

user_id | tariff_id
Putin | Cheap

最佳答案

解决方案 1:外键约束

我假设下表定义。特别是,user_tariffs 中的组合键使 userstariffs 之间成为多对多关系。

CREATE TABLE tariffs (tariff_id int NOT NULL PRIMARY KEY,  
reception text NOT NULL);
CREATE TABLE users (user_id int NOT NULL PRIMARY KEY,
reception text NOT NULL);
CREATE TABLE user_tariffs (tariff_id int NOT NULL REFERENCES tariffs (tariff_id),
user_id int NOT NULL REFERENCES users (user_id),
PRIMARY KEY (tariff_id, user_id));

您可能在某处需要所有三列的组合,所以让我们创建它:

ALTER TABLE user_tariffs ADD COLUMN reception text;  
UPDATE user_tariffs a
SET reception = b.reception
FROM (SELECT * FROM tariffs) b
WHERE a.tariff_id = b.tariff_id;
ALTER TABLE user_tariffs ALTER COLUMN reception SET NOT NULL;

现在我们可以使用 FOREIGN KEY REFERENCES (user_id, reception) 进入 users

CREATE UNIQUE INDEX ON tariffs (tariff_id, reception);  
ALTER TABLE user_tariffs ADD FOREIGN KEY (tariff_id, reception)
REFERENCES tariffs (tariff_id, reception);

此外,我们可以使用 FK REFs (tariff_id, reception)tariffs 中。

CREATE UNIQUE INDEX ON users (user_id, reception);  
ALTER TABLE user_tariffs ADD FOREIGN KEY (user_id, reception)
REFERENCES users (user_id, reception);

填充数据:

INSERT INTO users VALUES (1, 'cheap'), (2, 'expensive');
INSERT INTO tariffs VALUES (1, 'cheap'), (2, 'expensive');

现在假设我们有以下数据 (user_id, tariff_id) 要插入:

WITH data (user_id, tariff_id) 
AS (VALUES (1, 2), (2, 1)), -- here is your application data
datas (user_id, tariff_id, reception)
AS (SELECT user_id,
tariff_id,
(SELECT u.reception -- reception calculated by user
FROM users u
WHERE u.user_id = d.user_id)
FROM data d)
INSERT INTO user_tariffs SELECT * FROM datas ;

那你就不能插入数据了,因为你只能添加(1, 1)或者(2, 2)同一个reception,但不是 (1, 2)(2, 1) 具有不同的 reception。错误信息是:

ERROR:  insert or update on table "user_tariffs" violates foreign key constraint "user_tariffs_user_id_fkey1"
DETAIL: Key (user_id, reception)=(2, cheap) is not present in table "users".

但是您可以插入 data AS VALUES (1, 1), (2, 2)。我认为 FOREIGN KEY CONSTRAINT 解决方案是首选。

如果您想要更好的表格设计,请描述您的功能依赖项

解决方案 2:触发器

-- DROP TABLE user_tariffs CASCADE;  
-- DROP TABLE users CASCADE;
-- DROP TABLE tariffs CASCADE;
CREATE TABLE tariffs (tariff_id int NOT NULL PRIMARY KEY,
reception text NOT NULL);
CREATE TABLE users (user_id int NOT NULL PRIMARY KEY,
reception text NOT NULL);
CREATE TABLE user_tariffs (tariff_id int NOT NULL REFERENCES tariffs (tariff_id),
user_id int NOT NULL REFERENCES users (user_id),
PRIMARY KEY (tariff_id, user_id));
INSERT INTO users VALUES (1, 'cheap'), (2, 'expensive');
INSERT INTO tariffs VALUES (1, 'cheap'), (2, 'expensive');
-- table user_tariffs (user_id, tariff_id) only, without reception column.

创建一个返回类型触发器的函数:

CREATE OR REPLACE FUNCTION check_reception()  
RETURNS trigger AS $$
DECLARE valid boolean := false;
BEGIN
SELECT (SELECT u.reception FROM users u WHERE u.user_id = NEW.user_id)
= (SELECT t.reception FROM tariffs t WHERE t.tariff_id = NEW.tariff_id)
INTO valid FROM user_tariffs ;
IF valid = false
THEN RAISE EXCEPTION '(user, tariff, reception) invalid.';
END IF;
RETURN NEW;
END; $$ LANGUAGE plpgsql ;

并注册:

CREATE TRIGGER reception_trigger  
AFTER INSERT OR UPDATE ON user_tariffs
FOR EACH ROW EXECUTE PROCEDURE check_reception();

现在尝试插入 (1, 2),这是 (cheap, expensive) 并且是不允许的:

INSERT INTO user_tariffs VALUES (1, 2);
ERROR: (user, tariff, reception) invalid.
KONTEXT: PL/pgSQL function check_reception() line 7 at RAISE

但是我们可以插入 (1, 1),这是 (cheap, cheap) 没有问题的:

INSERT INTO user_tariffs VALUES (1, 1);
SELECT * FROM user_tariffs;

备注

在我看来,触发器并不是这里的最佳解决方案。如果可能,尽量避免触发。它们可能有副作用(交易等)。检查 StackOverflow 以获取更多详细信息:)

关于postgresql - 约束,基于与另一个表的连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44335366/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com