正确的方法来创建一个引用另一个表中的变量的表

时间:2011-12-07 19:11:52

标签: sql postgresql database-design

我有这些关系:

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作为表的名称是有问题的,所以忽略名称。

5 个答案:

答案 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子句。这两个版本在引用完整性方面是相同的,只有两种语法方法可以做到这一点。