我有这些关系:
User(uid:integer,uname:varchar)
,关键是uid
Recipe(rid:integer,content:text)
,关键是摆脱
Rating(rid:integer, uid:integer, rating:integer)
,关键是(uid,rid)。
我按以下方式构建了表:
CREATE TABLE User(
uid INTEGER PRIMARY KEY ,
uname VARCHAR NOT NULL
);
CREATE TABLE Recipes(
rid INTEGER PRIMARY KEY,
content VARCHAR NOT NULL
);
现在针对Rating
表格:我希望无法插入uid\rid
中不存在的User\Recipe
。
我的问题是:以下哪项是正确的方法?或者如果没有一个是正确的,请建议正确的方法。此外,如果有人能向我解释两者之间有什么区别,我真的很感激。
首先:
CREATE TABLE Rating(
rid INTEGER,
uid INTEGER,
rating INTEGER CHECK (0<=rating and rating<=5) NOT NULL,
PRIMARY KEY(rid,uid),
FOREIGN KEY (rid) REFERENCES Recipes,
FOREIGN KEY (uid) REFERENCES User
);
第二:
CREATE TABLE Rating(
rid INTEGER REFERENCES Recipes,
uid INTEGER REFERENCES User,
rating INTEGER CHECK (0<=rating and rating<=5) NOT NULL,
PRIMARY KEY(rid,uid)
);
编辑:
我认为User
作为表的名称是有问题的,所以忽略名称。
答案 0 :(得分:4)
从技术上讲,Postgres的两个版本都是相同的。 CREATE TABLE的文档说得非常清楚:
定义约束有两种方法:表约束和列约束。列约束定义为列定义的一部分。表约束定义不依赖于特定列,它可以包含多个列。每个列约束也可以写为表约束;列约束只是在约束仅影响一列时使用的符号方便。
因此,当您必须引用复合键时,表约束是唯一的方法。
但对于其他所有情况,我更喜欢最简短,最简洁的形式,我不需要为我不感兴趣的东西命名。所以我的版本会是这样的:
CREATE TABLE usr(
uid SERIAL PRIMARY KEY ,
uname TEXT NOT NULL
);
CREATE TABLE recipes(
rid SERIAL PRIMARY KEY,
content TEXT NOT NULL
);
CREATE TABLE rating(
rid INTEGER REFERENCES recipes,
uid INTEGER REFERENCES usr,
rating INTEGER NOT NULL CHECK (rating between 0 and 5),
PRIMARY KEY(rid,uid)
);
答案 1 :(得分:3)
这是一个基于SQL Server的解决方案,但该概念适用于大多数RDBMS。
像这样:
CREATE TABLE Rating (
rid int NOT NULL,
uid int NOT NULL,
CONSTRAINT PK_Rating PRIMARY KEY (rid, uid)
);
ALTER TABLE Rating ADD CONSTRAINT FK_Rating_Recipies FOREIGN KEY(rid)
REFERENCES Recipies (rid);
ALTER TABLE Rating ADD CONSTRAINT FK_Rating_User FOREIGN KEY(uid)
REFERENCES User (uid);
这可确保Rating
内的值仅为Users
表和Recipes
表中的有效值。请注意,在Rating
表中我没有包含您拥有的其他字段,只需添加这些字段。
假设在users表中有3个用户:Joe,Bob和Bill各自的ID为1,2,3。在食谱表中你有饼干,鸡肉馅饼和南瓜饼各自的ID是1,2,3。然后插入Rating表将只允许这些值,为RID输入4或UID SQL引发错误并且不提交事务。
亲自尝试,这是一次很好的学习经历。
答案 2 :(得分:1)
在Postgresql中,实现这些表的正确方法是:
CREATE SEQUENCE uid_seq;
CREATE SEQUENCE rid_seq;
CREATE TABLE User(
uid INTEGER PRIMARY KEY DEFAULT nextval('uid_seq'),
uname VARCHAR NOT NULL
);
CREATE TABLE Recipes(
rid INTEGER PRIMARY KEY DEFAULT nextval('rid_seq'),
content VARCHAR NOT NULL
);
CREATE TABLE Rating(
rid INTEGER NOT NULL REFERENCES Recipes(rid),
uid INTEGER NOT NULL REFERENCES User(uid),
rating INTEGER CHECK (0<=rating and rating<=5) NOT NULL,
PRIMARY KEY(rid,uid)
);
您编写的两个选项之间没有真正的区别。
答案 3 :(得分:0)
一个简单的(即单列)外键可以与列声明一致地声明。这只是一个风格问题。第三种方法应该是完全省略CREATE TABLE
的外键声明,然后使用ALTER TABLE
语句添加它们;在事务中完成(可以与所有其他表,约束等一起推测),如果没有所需的约束,表将永远不会存在。选择您认为最容易阅读和理解的人类编码器,即最容易维护。
答案 4 :(得分:-2)
REFERENCES
子句。这两个版本在引用完整性方面是相同的,只有两种语法方法可以做到这一点。