我正在马里兰州的约翰霍普金斯大学学习数据库,并有一个问题。我已经通过电子邮件发送了我的教授,他知道我在这里问这个问题而且他很酷。所以我正在Postgres开发一个COOKBOOK数据库,我在Postgres中遇到了一个有趣的问题,我似乎无法构建PRICE表。我有一个很好的食谱ERD,但显然不能发布,直到我的声誉至少10.我会尽我所能描述ERD。有三个与PRICE有关的保理表。这些是成分,替代品和价格。
这是ERD的链接(请注意1:M代表成分替换): [ERD]
我可以拥有一个可能有多个替代品的成分,并且可能在SUBSTITUTION和PRICE之间一对一(如果已知PRICE,则每个替换一个PRICE)。如果PRICE已知,那么PRICE能够定义具有复合主键的元组:(price_id,ingredient_id(fk),substitution_id(fk))
我面临的挑战是Postgres SQL不允许我建立这种关系,我不确定为什么。我已经将SUBSTITUTION中的键设置为具有UNIQUE约束,因此不应该是问题。我唯一能想到的是,SUBSTITUTION中的ingredient_id是INGREDIENT的外键,因此可能无法在SUBSTITUTION中实际建立,但我得到的错误并不表明这一点。这就是我在终端中获得的内容(首先描述了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 :(得分:3)
' ave省略了一些列,因此您可以专注于键。我几乎没看一眼你的ERD。 (我讨厌一千个太阳的燃烧激情的NERD。)
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)
);
答案 1 :(得分:0)
问题是因为FOREIGN KEY
表price
中定义的substitution(ingredient_id)
不是唯一的。
在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约束 - 它不是唯一的。我上面提到的同样类型的补救措施也适用于该栏目。
答案 2 :(得分:-2)
**更新:2014-11-02决定放弃PRICE表。我的教授说,将两个独立的价格属性吸收到INGREDIENT和SUBSTITUTION实体类型中会很好。他说我像往常一样努力思考。 **
解决了问题!感谢所有人的反馈。这个网站非常好。这是最终的解决方案布局:
按此顺序构建INGREDIENT,SUBSTITUTION和PRICE ......
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)
);
如果有人有兴趣,我会在我的所有SQL脚本中添加一个github并链接。我正在制作一个带有ERD和12个表的COOKBOOK数据库。应该是一个有趣的项目。再次感谢您的帮助。