如何创建一个表,其行引用2个现有表中的1个(且仅1个)?

时间:2016-01-13 08:09:33

标签: sql sql-server tsql database-design

这是我的情况:我有两个用

创建的表
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)
);

但是我将如何制作它以便如果删除了SolutionRating s相对应的{{1}},那么这些评分就会太多?????

2 个答案:

答案 0 :(得分:0)

您基本上有两个选项,但这是一个回顾和检查数据库结构的好机会。

第一个选择是做这样的事情:

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的并集,那么您可以考虑是否可以重构数据库结构以反映这一点,因此您只需要一个表来链接。 / p>

答案 1 :(得分:0)

两张桌子看起来非常相似没有错。它们包含不同的内容,您无需选择所有三星评级,无论是在问题还是解决方案上 - 您总是可以使用解决方案评级问题评级。

但是要在一个表格中同时使用两个评级也没有错误,并且当您希望评级表现相同时,无论是在问题还是解决方案上(例如两者都有1到5颗星,两者都可以有)评论不再是200个字符,...)。

这可以通过简单地给予评级表一个problem_id和一个带有外键的solution_id并完全填写其中一个或另一个来完成。使用自然键,同样会感觉更自然,更自然:

  • problem(problem_no, data)
  • solution(problem_no, solution_no, data)
  • rating(problem_no, solution_no, data)

在两个父表上都有rating.solution_no个可空和外键。