【发布时间】:2020-10-23 20:09:56
【问题描述】:
我正在尝试在 PostgreSQL 11.7 中实现一个数据库,它应该代表几个嵌套复合类型的层次结构。目前我有以下定义(简化):
CREATE TYPE type_school as (code integer, descr text);
CREATE TYPE type_district as (code integer, descr text, schools type_school[]);
CREATE TYPE type_city as (code integer, descr text, districts type_district[]);
CREATE TYPE type_country as (code integer, descr text, cities type_city[]);
还有一张桌子:
CREATE TABLE countries (country type_country);
例如,这些应该是有效记录(descr 列是可选的,不感兴趣):
代码为 1 的国家/地区,城市 3,4,5,地区为 {1,2}、{1,3}、{3,6}
国家代码 2,城市 3,6,地区 {3,7}, {7,9}
为了填充表格,我对国家/地区使用 INSERT,对其他元素使用 UPDATE:
INSERT INTO countries values(ROW(1, 'country descr', ARRAY[]::type_city[]));
UPDATE countries SET(country.city[1].code, country.city[1].descr) = (1, 'city descr') WHERE (country).code = 1;
UPDATE countries SET(country.city[1].district[2].code, country.city[1].district[2].descr) = (2, 'district descr') WHERE (country).code = 1;
此设置工作正常,因为我可以执行大部分必要的查询。但是,我认为这不是正确的方法。我是一名 C 程序员,没有数据库编程经验。我将这种排列视为struct 元素的数组,由更多struct 数组组成。而且我习惯于通过索引来访问元素,这就是你在这个实现中看到的。我想拥有数据库的一些特性,比如约束。然而,这些在 PostgreSQL 类型上是不可能的,只能在表上。如果我将数组定义为表,我不知道如何编写INSERT 查询来访问内部表。根据一些网站,在 PostgreSQL 中嵌套表是不可能的,他们建议使用数组。是否可以在复合类型数组中强制执行约束?我在网上找到的另一个建议是使用 ltree 扩展名。但是在我看来,树元素都是相同的类型,并且每个级别都有不同的类型。同样在我当前的实现中,我不知道如何删除某个元素及其所有子元素。所以我的问题是:
应该如何实现一个表来表示一个树状结构,由 4 个级别组成,每个级别代表一种不同的类型,以便可以为每种类型的元素指定约束?甚至可以用关系数据库来做到这一点吗?为了清楚起见,我要区分元素的只是一个索引,每个元素仅通过其路径 country[i]->city[j]->district[k]->school[l] 唯一标识。
【问题讨论】:
-
不,这都是错误的。规范化数据库模型:每列应该只包含一个(“原子”)值。将数据放在具有外键关系的不同表中。
-
这是否意味着底部表(学校)应该有 3 个外键 - 国家、城市和地区,而一个地区将有 2 个国家和城市?
-
school将有一个到district的外键,district将有一个到city的外键,city将有一个到country的外键。要选择数据,请加入表格;这是非常有效的。 -
好的,但是由于我可以在不同的国家和城市有重复的城市或地区代码,我如何创建外键?如果城市的主键是 (country_code, city_code) 我可以将国家 1 与城市 1,2 和国家 2 与城市 1,2。但是如何将此组合引用为区域中的外键?
-
那么外键必须同时引用它们。人们通常使用人工生成的数字主键来避免这种情况,但主键由两列组成是没有问题的。
标签: database postgresql