1

質問:

外部IDが1つの特定のテーブルよりも一般的なものを指すようにする方法はありますか?

詳細:

互いに関係のないテーブルがいくつかあるが、それでも共通のテーブルが必要な状況に遭遇することがよくあります(以下の例ではエンジンは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個の新しいテーブルを作成せずにそのような状況を処理するためのより正しい方法はありますか?history1つのテーブルを作成してそれをコピーできることに気付きましCREATE TABLE...LIKE...たが、それでもn個の新しいテーブルを作成する必要があります。さらにALTER、に入る必要がありforeign_idます。

4

3 に答える 3

2

私が最初に考えたのは、fk 参照をダンプして、1 つの履歴テーブルを作成することです。

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 でもあります (ただし、自動インクリメント列ではありません)。
  • 「movie」レコードの ID として使用される生成された ID を返す「キー」にレコードを挿入する「movies」に「挿入前」トリガーを追加します。
  • 「キー」への fk を使用して履歴テーブルを作成する
  • 整合性を維持したい場合、またはカスケード削除などの場合は、「キー」からレコードを削除する「ムービー」に「削除」トリガーを作成します。

したがって、生成された「id」は多くのテーブルで共有されます。データベース内のすべての関係で一意の主キー (「エンタープライズ キー」) を使用することを提案する考え方があるため、これは前例のないことではありません。シーケンスまたは自動生成された列を使用する代わりに、GUID または UUID が使用されることがあります。

これにより、余分な履歴テーブルが各ベース テーブルのトリガーに置き換えられますが、環境によっては、これは良いことではないかもしれません。私はこれを自分で行ったわけではなく、いくつかの考えをそこに放り込んでいるだけなので、その価値を理解してください.

于 2012-05-01T01:56:09.143 に答える
1

これは、保持している記録によって異なります。ヒット数だけを知りたい場合は、各テーブルに 1 つのフィールドを追加します。このフィールドは、「ヒット」基準が満たされる (つまり、Web ページからの読み取りがある) たびに増加します。より多くの情報を保持したい場合:

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

1 つの外部キーで複数のテーブルを指定する方法はないと思います。

単一の履歴テーブルを定義する場合、単一の外部キーを使用して参照整合性を強制することはできません。here で説明されているように、プログラムで強制できます

これは、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 に答える