如何创建一个表,其行引用 2 个现有表中的 1 个(且仅 1 个)?
Posted
技术标签:
【中文标题】如何创建一个表,其行引用 2 个现有表中的 1 个(且仅 1 个)?【英文标题】:How do I create a table whose rows reference 1 (and only 1) of 2 existing tables? 【发布时间】:2016-01-13 08:09:32 【问题描述】:这是我的情况:我有两个用
创建的表CREATE DATABASE JsPracticeDb;
/* Create tables corresponding to the problems, solutions to
problems, and ratings of problems or solutions */
CREATE TABLE Problems (
id INT PRIMARY KEY NOT NULL,
prompt_code VARCHAR(3000),
test_func_code VARCHAR(3000),
test_input_code VARCHAR(3000)
);
CREATE TABLE Solutions (
id INT PRIMARY KEY NOT NULL,
problem_id INT,
solver_name VARCHAR(50),
code VARCHAR(3000),
FOREIGN KEY (problem_id) REFERENCES Problems(id) ON DELETE CASCADE,
);
我正在考虑为Solutions
创建一个评级表,我将其写为
CREATE TABLE Ratings (
id INT PRIMARY KEY NOT NULL,
solution_id INT,
stars TINYINT,
FOREIGN KEY (solution_id) REFERENCES Solutions(id) ON DELETE CASCADE
);
但后来我意识到我实际上可能也想给Problems
评分。在我看来,“蛮力”解决方案是
CREATE TABLE SolutionRatings (
id INT PRIMARY KEY NOT NULL,
solution_id INT,
stars TINYINT,
FOREIGN KEY (solution_id) REFERENCES Solutions(id) ON DELETE CASCADE
);
CREATE TABLE ProblemRatings (
id INT PRIMARY KEY NOT NULL,
problem_id INT,
stars TINYINT,
FOREIGN KEY (problem_id) REFERENCES Problems(id) ON DELETE CASCADE
);
但我的编程直觉表明,我使用复制粘贴来编写几乎相同的两段代码这一事实存在问题。但是,我想不出任何使用交集表或类似也允许我进行级联删除的替代解决方案。例如,我知道我可以做到
CREATE TABLE RatedTables (
id TINYINT PRIMARY KEY NOT NULL,
table_name VARCHAR(9)
);
INSERT INTO RatedTables (table_name) VALUES ('Problems','Solutions');
CREATE TABLE Ratings (
id INT PRIMARY KEY NOT NULL,
rated_table_id TINYINT NOT NULL,
stars TINYINT,
FOREIGN KEY (rated_table_id) REFERENCES RatedTables(id)
);
但是我将如何做到这一点,如果Solution
和相应的Rating
s 被删除,那么这些评级也会太?????
【问题讨论】:
如何使用外键约束 FOREIGN KEY(problem_id) REFERENCES Problems(id) ON DELETE CASCADE 将另一列添加到 Ratings 表 problem_id int 【参考方案1】:您基本上有两个选择,但这是返回并查看您的数据库结构的好机会。
第一种选择是这样做:
CREATE TABLE potential_link1 (
id int primary key,
...
);
CREATE TABLE potential_link2 (
id int primary key,
....
);
CREATE TABLE ratings (
id int primary key,
potential_link1 int references potential_link1(id) on delete cascade,
potential_link2 int references potential_link2(id) on delete cascade,
....
check(potential_link1 is null or potential_link2 is null),
check(potential_link2 is not null or potential_link1 is not null)
);
这可行,但您可以看到它有点复杂。
第二种可能性是,由于存在明显的情况 a 依赖于 b 和 c 的联合,那么您可能会考虑是否可以重构您的数据库结构以反映这一点,因此您只需要一个表来链接。
【讨论】:
在 OP 的情况下,他们已经在potential_link1
和 potential_link2
之间有一个带有 on delete cascade
的 FK 引用。所以我认为你不能用on delete cascade
在ratings
中创建这些外键(因为SQL Server 的over-eager 循环检测器)【参考方案2】:
两张看起来如此相似的桌子并没有错。它们包含不同的内容,无论是针对问题还是解决方案,您都不想选择所有三星级评级 - 您将始终使用解决方案评级或问题评级。
但是在一个表中同时包含两个评分也没有错,当您希望评分表现相同时,无论是在问题还是解决方案上(例如,两者都应该有 1 到 5 星,两者都可以有),这也是一个好主意评论不再超过 200 个字符,...)。
这可以通过简单地为评级表提供一个问题_id 和一个解决方案_id 以及表上的外键并始终填充一个或另一个来完成。使用自然键,感觉会更加自然:
problem(problem_no, data)
solution(problem_no, solution_no, data)
rating(problem_no, solution_no, data)
在两个父表上都有rating.solution_no
可为空和外键。
【讨论】:
以上是关于如何创建一个表,其行引用 2 个现有表中的 1 个(且仅 1 个)?的主要内容,如果未能解决你的问题,请参考以下文章
如何将现有表中的 7000 条记录中的前 1000 条记录复制到其他新表中