0

我正在马里兰州的约翰斯霍普金斯大学学习数据库课程并且有一个问题。我已经发邮件给我的教授,他知道我在这里问这个问题,他很酷。所以我在Postgres开发了一个COOKBOOK数据库,并且我在Postgres中遇到了一个有趣的问题,我似乎无法构建PRICE表。我有一个不错的食谱ERD,但显然不能发布,直到我的声誉至少10。我会尽我所能来形容ERD。有三个与价格相关的保理表格。这些是成分,替代品和价格。Postgres综合主键依赖问题

下面是对ERD的链接(注意1:M为配料替代): [ERD]

我可以有一个成分与潜在的许多替换和可能的一个到一个取代之间和价格(如果知道价格,每个替代品一个价格)。如果PRICE已知,则PRICE能够定义具有复合主键的元组:(price_id,ingredient_id(fk),substitution_id(fk))

我面临的挑战是Postgres SQL不允许我建立这种关系,我不确定为什么。我已经将SUBSTITUTION中的键设置为具有UNIQUE约束,所以不应该成为问题。我唯一能想到的是,SUBSTITUTION中的ingredient_id是INGREDIENT的外键,因此可能不会在SUBSTITUTION中物理建立,但我得到的错误并不表明这一点。这是我在终端我得到(第一描述代换):

cookbook=# \d+ SUBSTITUTION 
                  Table "public.substitution" 
    Column  |   Type   |        Modifiers         | Storage | Description 
    --------------------+-----------------------+--------------------------------------------------------------------------+----------+------------- 
    substitution_id | integer    | not null default nextval('subsitution_substitution_id_seq'::regclass) | plain | 
    ingredient_id  | integer    | not null default nextval('subsitution_ingredient_id_seq'::regclass)  | plain | 
    name    | character varying(50) | not null                 | extended | 
    measurement_ref_id | integer    | not null default nextval('subsitution_measurement_ref_id_seq'::regclass) | plain | 
    metric_unit  | character varying(25) | not null                 | extended | 
    Indexes: 
    "subsitution_pkey" PRIMARY KEY, btree (substitution_id, ingredient_id) 
    "uniqueattributes" UNIQUE, btree (substitution_id, ingredient_id) 
    Foreign-key constraints: 
    "subsitution_ingredient_id_fkey" FOREIGN KEY (ingredient_id) REFERENCES ingredient(ingredient_id) 
    "subsitution_measurement_ref_id_fkey" FOREIGN KEY (measurement_ref_id) REFERENCES measurement_ref(measurement_ref_id) 
    Has OIDs: no 

    cookbook=# create table price(
    price_id serial not null, 
    ingredient_id serial references substitution(ingredient_id), 
    cookbook(# substitution_id serial references substitution(substitution_id), 
    cookbook(# usdollars smallint not null, 
    cookbook(# availability season, 
    cookbook(# seasonal boolean, 
    cookbook(# primary key (price_id, ingredient_id, substitution_id) 
    cookbook(#); 
    NOTICE: CREATE TABLE will create implicit sequence "price_price_id_seq" for serial column "price.price_id" 
    NOTICE: CREATE TABLE will create implicit sequence "price_ingredient_id_seq" for serial column "price.ingredient_id" 
    NOTICE: CREATE TABLE will create implicit sequence "price_substitution_id_seq" for serial column "price.substitution_id" 
    NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "price_pkey" for table "price" 
    ERROR: there is no unique constraint matching given keys for referenced table "substitution" 
+0

我不知道我是否真的理解,外键在它自己的表中必须是唯一的,如果你想引用元组:substitition_id和ingredient_id,你可以添加一个像'ingredient_subtition_id'这样的列作为连续序列到你的'替代'表,并将其作为主键,则可以将此键作为“价格”表中的外键引用。 – Houari 2014-10-28 20:50:41

+0

@Houari添加一个键&FK并不能阻止PRICE(substitution_id,ingredient_id)对SUBSTITUTION的限制。你的建议所做的是有一个FK存在,但没有影响是原始预期约束点。 – philipxy 2014-11-08 09:41:29

回答

3

我省略了一些列,所以您可以专注于按键。我几乎没有看你的ERD。 (我恨一千个太阳燃烧激情ERDs)

create table ingredients (
    ingredient_id serial primary key, 
    -- Don't allow duplicate names. 
    ingredient_name varchar(35) not null unique 
); 

create table substitutions (
    -- These are properly declared integer, not serial. 
    -- Also note two separate foreign key references. 
    ingredient_id integer not null references ingredients (ingredient_id), 
    substitute_id integer not null references ingredients (ingredient_id), 
    primary key (ingredient_id, substitute_id) 
); 

create table prices (
    -- Price id number is unnecessary. 
    ingredient_id integer not null, 
    substitute_id integer not null, 
    -- Money is usually declared numeric(n, m) or decimal(n, m). 
    us_dollars numeric(10, 2) not null 
    -- Negative amounts don't make sense. 
    check (us_dollars >= 0), 
    -- Only one row per distinct substitution. 
    primary key (ingredient_id, substitute_id), 
    -- One single foreign key reference, but it references *two* columns. 
    foreign key (ingredient_id, substitute_id) references substitutions (ingredient_id, substitute_id) 
); 
+0

我收回我原来的评论。是的,这工作。我会发布更新。您对SUBSTITUTE和INGERDIENTS的SQL已经过时了,但是对于PRICE的创建表是现成的。此外,当您命名表格时,最好将它们命名为单数而非复数(例如PRICE而非PRICES)。 – 2014-10-29 03:29:03

+1

+1用于燃烧反ERD激情! !!!!! ! ! !!!!!!!!!! – philipxy 2014-11-08 09:27:46

0

的问题是因为在price表,substitution(ingredient_id)定义的FOREIGN KEY,是不是唯一的。

substitution表,你有以下指标定义:

"subsitution_pkey" PRIMARY KEY, btree (substitution_id, ingredient_id) 
    "uniqueattributes" UNIQUE, btree (substitution_id, ingredient_id) 

这意味着,该表目前唯一需要元组的(substitution_id, ingredient_id)。顺便说一句,这两个索引真的是相互重复的,因为PRIMARY KEY约束通过定义来保证唯一性。

所以,你有很多选择,但是我发现最简单的事情往往是使用一个唯一的ID来为每个表定义 - 我喜欢使用id serial,它会创建一个隐式序列,并且然后将其定义为PRIMARY KEY

然后,您可以使用该键来定义FOREIGN KEY关系。在使用多键元组的同时,这确实使事情变得复杂,并且我发现使用单个ID更容易。如果您需要SELECT性能等等,您可以随时在多键元组上创建额外的唯一索引。

同样的情况适用于ingredient_id上的FK约束 - 它不是唯一的。我上面提到的同样类型的补救措施也适用于该专栏。

+0

那么我很乐意实现那个单一的PK。这将是很好的,但我受到限制(无双)适用于多个键符合我的ERD设计。他不希望我们削减任何角落,但我同意你的方法是我在现实世界中实施的方法(是的,我做了一些数据库工作)。我尝试了以下操作,以确保您的建议的ingredient_id是唯一的:alter table ingredient add constraint uniqueingredientid UNIQUE(ingredient_id);希望能够解决这个问题,并且仍然会得到相同的“不唯一”的错误。我究竟做错了什么? – 2014-10-28 21:10:37

+0

我不会说单一的PK方法是“偷工减料” - 我认为它实际上更多的是相反的,因为它本质上是一个额外的而不仅仅是使用多键元组。该任务是否明确禁止单个PK?你真的可以在'成分'上添加'UNIQUE'约束,然后错误出现在'substitution'的FK中吗? – khampson 2014-10-29 02:03:36

+0

是的,我不能那样做。需要使用复合键遵循严格的ERD设计。管理解决问题。看看我的答案。我明天会玩这个,以确保1NF,2NF和3NF。 – 2014-10-29 03:37:12

-2

**更新:2014年11月2日决定只是删除PRICE表。我的教授说可以将两个单独的价格属性吸收到INGREDIENT和SUBSTITUTION实体类型中。他说我像往常一样努力想着。 **

问题解决了!感谢大家的所有反馈。这个网站真的很不错。下面是最终的解决方案布局:

的顺序构建成分替换和价格...

create table INGREDIENT(
     ingredient_id serial not null, 
     description text, 
     amount smallint, 
     measurement_ref_id serial references measurement_ref(measurement_ref_id), 
     nutritional_info_id serial references nutritional_info(nutritional_info_id), 
     primary key (ingredient_id) 
    ); 

    create table SUBSTITUTION(
     substitution_id serial not null unique, 
     ingredient_id serial not null references ingredient(ingredient_id), 
     name varchar(50) not null, 
     measurement_ref_id serial references measurement_ref(measurement_ref_id), 
     metric_unit varchar(25) not null, 
     primary key (substitution_id, ingredient_id) 
    ); 

    -- NOTE: I'll add the other variables to this later. 
    CREATE TABLE PRICE(
     ingredient_id serial not null, 
     substitution_id serial not null, 
     -- link the two keys from substitution in as two unique foreign keys 
     foreign key (ingredient_id, substitution_id) references substitution (ingredient_id, substitution_id), 
     -- combine foreign keys as one single composite primary key 
     primary key (ingredient_id, substitution_id) 
    ); 

如果有人有兴趣,我把一个GitHub的,在我所有的SQL脚本的链接。我正在制作一个带有ERD和12个表格的COOKBOOK数据库。应该是一个有趣的项目。再次感谢你的帮助。

+1

Stil错误。 PRICE表中的{ingredient_id,substitution_id}应该是“INTEGER NOT NULL”而不是“serial”它们只是指INGREDIENT和SUBSTITUTION表的PK。 – wildplasser 2014-11-02 15:05:32

+0

@wildplasser我决定不走这条路。我想我最终会在这条路上取消这篇文章。 – 2014-11-10 04:20:41