我有一个包含四个表的PostgreSQL数据库:用户、国家、城市和街道。用户表包含有关用户的信息,包括他们的姓名、级别(可以是“国家”、“城市”或“街道”)以及与他们所属的“国家”、“城市”和“街道”的ID相对应的id。
表格结构:
CREATE TABLE "user" (
id INT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
level VARCHAR(10) NOT NULL, --ENUM('Country', 'City', 'Street')
id_country INT NULL,
id_city INT NULL,
id_street INT NULL,
FOREIGN KEY (id_country) REFERENCES Country(id) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (id_city) REFERENCES City(id) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (id_street) REFERENCES Street(id) ON UPDATE CASCADE ON DELETE CASCADE
);
x
CREATE TABLE Country (
id INT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
code INT NOT NULL
);
CREATE TABLE City (
id INT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
code INT NOT NULL,
id_country INT NOT NULL,
FOREIGN KEY (id_country) REFERENCES Country(id) ON UPDATE CASCADE ON DELETE CASCADE
);
CREATE TABLE Street (
id INT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
code INT NOT NULL,
id_city INT NOT NULL,
FOREIGN KEY (id_city) REFERENCES City(id) ON UPDATE CASCADE ON DELETE CASCADE
);
的数据
我想在User表和其他三个表之间建立适当的关系,这样我就可以根据用户的级别直接访问相应的“Country”、“City”或“Street”。我目前的方法包括为每种情况添加三个单独的列(id_country、id_city、id_street)和三个连接操作,这似乎是重复的,不是理想的设计。
我的用例的一个例子是:
switch (user.level) {
case "Country":
query = ' SELECT * from "user" AS u
INNER JOIN country c ON u.id_country = c.id '
break;
case "City":
query = ' SELECT * from "user" AS u
INNER JOIN city c ON u.id_city = c.id '
break;
case "Street":
query = ' SELECT * from "user" AS u
INNER JOIN street s ON u.id_street = s.id '
break;
}
型
是否有一种更有效、更简洁的方法来在User表中表示这些关系,同时保持数据完整性并遵守标准数据库设计原则?
我想到了使用这样的复合外键
CREATE TABLE "user" (
id INT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
location_id INT NOT NULL,
location_type VARCHAR(10) NOT NULL, --ENUM('Country', 'City', 'Street')
FOREIGN KEY (location_id, location_type) REFERENCES Country(id, 'Country' )
ON UPDATE CASCADE
ON DELETE CASCADE,
FOREIGN KEY (location_id, location_type) REFERENCES City(id, 'City' )
ON UPDATE CASCADE
ON DELETE CASCADE,
FOREIGN KEY (location_id, location_type) REFERENCES Street(id, 'Street' )
ON UPDATE CASCADE
ON DELETE CASCADE
);
型
但是,SQL不接受静态值作为引用。我没有SQL的高级知识。
如有任何改进数据库设计的建议或替代办法,将不胜感激。谢谢你,谢谢
2条答案
按热度按时间xtupzzrd1#
你可以选择这样做:
字符串
因此,user有一个简单的外键,指向一个名为geo_entity的东西-它适用于任何类型的实体:国家、城市或街道,视情况而定。geo_entity行可以有另一个geo_entity行作为其父行。
如果将user加入geo_entity,并查看geo_entity中的“level”设置,则会告诉您这是用户的级别。
如果有帮助,您还可以基于geo_entity创建国家、城市和街道视图。
06odsfpq2#
您的3个表(国家,城市,街道)设计正确。但是要小心FK中的CASCADE模式,并在PK中添加IDENTITY...
您的主表设计不正确,应按以下方式创建:
字符串
然后添加一个视图以完成:
型