1

问题:

有没有办法让外国 ID 指向比一个特定表更通用的东西?

细节:

我经常遇到这样的情况,我有几个彼此无关的表,但仍然需要一个公用表(在下面的示例中,引擎是innodb

CREATE TABLE IF NOT EXISTS movies
(
   id    INT NOT NULL auto_increment,
   name  VARCHAR(100) NOT NULL ,

   PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS books
(
   id    INT NOT NULL auto_increment,
   name  VARCHAR(100) NOT NULL ,

   PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS songs
(
   id    INT NOT NULL auto_increment,
   name  VARCHAR(100) NOT NULL ,

   PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS news_papers
(
   id    INT NOT NULL auto_increment,
   name  VARCHAR(100) NOT NULL ,

   PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS scrolls
(
   id    INT NOT NULL auto_increment,
   name  VARCHAR(100) NOT NULL ,

   PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS sumarian_wheat_tablets
(
   id    INT NOT NULL auto_increment,
   name  VARCHAR(100) NOT NULL ,

   PRIMARY KEY(id)
);

现在我想记录每次被这样查看的时间

CREATE TABLE IF NOT EXISTS movie_history
(
   id          INT NOT NULL auto_increment,
   foreign_id  INT NOT NULL ,
   view_date   TIMESTAMP DEFAULT now(),

   FOREIGN KEY (foreign_id) REFERENCES movies ( id ),
   PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS book_history
(
   id          INT NOT NULL auto_increment,
   foreign_id  INT NOT NULL ,
   view_date   TIMESTAMP DEFAULT now(),

   FOREIGN KEY (foreign_id) REFERENCES books ( id ),
   PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS song_history
(
   id          INT NOT NULL auto_increment,
   foreign_id  INT NOT NULL ,
   view_date   TIMESTAMP DEFAULT now(),

   FOREIGN KEY (foreign_id) REFERENCES songs ( id ),
   PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS news_paper_history
(
   id          INT NOT NULL auto_increment,
   foreign_id  INT NOT NULL ,
   view_date   TIMESTAMP DEFAULT now(),

   FOREIGN KEY (foreign_id) REFERENCES news_papers ( id ),
   PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS scroll_history
(
   id          INT NOT NULL auto_increment,
   foreign_id  INT NOT NULL ,
   view_date   TIMESTAMP DEFAULT now(),

   FOREIGN KEY (foreign_id) REFERENCES scrolls ( id ),
   PRIMARY KEY(id)
);

CREATE TABLE IF NOT EXISTS sumarian_wheat_tablet_history
(
   id          INT NOT NULL auto_increment,
   foreign_id  INT NOT NULL ,
   view_date   TIMESTAMP DEFAULT now(),

   FOREIGN KEY (foreign_id) REFERENCES sumarian_wheat_tablets ( id ),
   PRIMARY KEY(id)
);

有没有更正确的方法来处理这种情况而无需创建 n 个新表?我意识到我可以制作一张history表格并将其复制过来,CREATE TABLE...LIKE...但这仍然需要制作 n 个新表格,而且我必须ALTER进入foreign_id.

4

3 回答 3

2

我的第一个想法就是转储 fk 引用并拥有一个历史表:

CREATE TABLE history(
   base_table    VARCHAR,
   base_table_id INT,
   view_date     TIMESTAMP DEFAULT now()
);

但是我假设您希望 fk 保持完整性(问题:这真的有必要吗,或者可以解决这个问题吗?)。我想你可以通过创建一个“正在使用的 pks”表来实现这一点。例如:

  • 使用列 id (autoincrement) 和 base_table_name 创建一个表“keys”
  • 创建一个表“movies”,其中 id 既是 pk 也是“keys.id”的 fk(但不是自动增量列)
  • 将“插入前”触发器添加到“电影”,将记录插入“键”,返回生成的 ID,用作“电影”记录的 ID
  • 创建一个带有 fk 到“keys”的历史表
  • 在“电影”上创建一个“删除”触发器,如果​​您希望保持完整性或级联删除等,它也会从“键”中删除记录

因此生成的“id”在许多表中共享。有一种思想流派建议在数据库内的所有关系中使用唯一的主键(“企业键”),因此它并非史无前例。有时使用 GUID 或 UUID,而不是使用序列或自动生成的列。

这用每个基表上的触发器替换了额外的历史表,这可能不是一件好事,具体取决于您的环境。我自己没有这样做,只是把一些想法扔在那里,所以把它当作它的价值。

于 2012-05-01T01:56:09.143 回答
1

这取决于您保留的记录。如果您只想了解命中,请在每个表中添加一个字段,每次满足您的“命中”条件时(即从网页读取),该字段就会递增。如果您想保留更多信息:

CREATE TABLE IF NOT EXISTS view_history
(
   id          INT NOT NULL,
   table       VARCHAR NOT NULL,
   //other relevant stats to a given view, such as ip and so on.
)

id 和 table 形成了一个组合键,用于确定它所指的表。

于 2012-05-01T01:04:35.430 回答
1

我认为没有一种方法可以在单个外键上指定多个表。

如果定义单个历史表,则不能使用单个外键强制引用完整性。您可以按照此处的说明以编程方式强制执行它

这描述了如何为不支持 FK 的其他存储引擎执行此操作,但可以用作实现所需内容的指南。它建议创建触发器来强制执行与外键相同的验证。

其他方法:

CREATE TABLE IF NOT EXISTS history
(
   id            INT NOT NULL auto_increment,
   movie_id      INT,
   book_id       INT,
   song_id       INT,
   news_paper_id INT,
   view_date   TIMESTAMP DEFAULT now(),


   FOREIGN KEY (movie_id) REFERENCES movie ( id ),
   FOREIGN KEY (book_id) REFERENCES book ( id ),
   FOREIGN KEY (song_id) REFERENCES song ( id ),
   FOREIGN KEY (news_paper_id) REFERENCES news_paper ( id ),
   PRIMARY KEY(id)
);
于 2012-05-01T01:44:09.717 回答