web-dev-qa-db-ja.com

リレーショナルデータベースの複合としての自動インクリメントキーと外部キー

私は、ワークベンチで遊んだり、プロジェクト用にこのデータベースを設定する方法を理解したりすることから得たもの以外に、データベースの経験はありません。私はインターネットを検索していて、自分がやりたいことをどのように行うのかについて、ますます混乱しています。以下は私が達成しようとしていることです。

患者情報を保持するMySQLデータベースが必要です。患者情報は、名前、ID(一意)など、すべてのテストと各テストのサンプルになります。

  • 各患者は複数の検査を受けることができます
  • 各テストには複数のサンプルを含めることができます
  • 患者を削除すると、すべてのテストとサンプルが削除されます
  • テストを削除すると、すべてのサンプルが削除されます
  • 1つのテストのすべてのサンプルを削除する場合OR 1人の患者のすべてのテストの場合、テストOR患者は削除しないでください。

これまでのところ、リレーショナルデータベースが必要であることを理解しています。また、外部キーを使用して各テーブルの患者IDと各テーブルのテストIDをリンクできることも理解しています。また、行の削除と更新を手動で管理する必要がないように、データの整合性が必要であるという結論にも達しました。これも孤立した行を許可しません。これは複合キーで実行できると思いますが、ここで設定方法が混乱し始めます。

私はそれが次のように機能することを期待します(各行が挿入ステートメントです):

患者テーブル:

|-------------------|
|Patient ID  |Name  |
|-------------------|
|12345       |ANG   |
|54321       |JUE   |
|-------------------|

テストテーブル:

|----------------------|
|Test ID  |Patient ID  |
|----------------------|
|1        |12345       |
|2        |12345       |
|3        |12345       |
|1        |54321       |
|2        |54321       |
|4        |12345       |
|----------------------|

サンプルテーブル:

|----------------------------------|
|Sample ID  |Test ID  |Patient ID  |
|----------------------------------|
|1          |1        |12345       |
|2          |1        |12345       |
|3          |1        |12345       |
|1          |2        |12345       |
|1          |1        |54321       |
|1          |2        |54321       |
|2          |2        |54321       |
|2          |2        |12345       |
|----------------------------------|

これは簡単にできますか?これは1つまたは2つのトリガーで実行できることも知っていますが、削除などを処理しないことを理解しました。これを実行するのが簡単な別の方法はありますか?また、このデータベースに書き込まれたり読み取られたりするデータは、LabVIEWプログラムによって処理されます。

4
altech6983

Joel、Greenstone、Stolegに感謝します。さらに調査した後、y'allのコメントと回答は、自分が必要なものを理解するのに役立ちました。トリガーとデータの整合性に関しては、考えすぎていたことがわかりました。

必要なものの要約:

患者テーブル:なし

テストテーブル:一意の外部キー(Patient ID)ごとに、Test IDは1から始まります

サンプルテーブル:一意の複合外部キー(Test ID AND Patient ID)ごとに、Sample IDは1から始まります。

  • 各患者は複数の検査を受けることができます
  • 各テストには複数のサンプルを含めることができます
  • 患者を削除すると、すべてのテストとサンプルが削除されます
  • テストを削除すると、すべてのサンプルが削除されます
  • 1つのテストのすべてのサンプルを削除する場合OR 1人の患者のすべてのテストの場合、テストOR患者は削除しないでください。

回答:

これは、トリガーを使用して実装し、データの整合性を維持するのが非常に簡単です。 Joelが言うように、データは非常に直接的な構造であり、多数のsamplesから1つtest、多数のtestsから1つpatientがあり、一意のみです。 patientsテーブルのpatient。これにより、カスケードを使用して孤立を防止し、データの整合性を維持できます。カスケードを設定すると、必要なすべての項目が満たされます。ジョエルの例:

...
CONSTRAINT 'FK_TEST__PATIENT' FOREIGN KEY ('patient_id')
      REFERENCES 'PATIENT' ('patient_id') ON DELETE CASCADE
...
CONSTRAINT 'FK_SAMPLE__TEST' FOREIGN KEY ('test_id')
      REFERENCES 'TEST' ('test_id') ON DELETE CASCADE
...

次の部分は、一意のキーまたは複合キーごとに自動インクリメント(これは組み込みのauto-incではありません)をリセットすることでした。これは、BEFORE INSERTトリガーを使用して実行できます。 (クレジットは Devart に移動します)

これは私のtestテーブルの変更されたトリガーです:

delimiter $$
CREATE TRIGGER `insert_test_auto_inc`
  BEFORE INSERT
  ON `tests`
  FOR EACH ROW

BEGIN
  SELECT COALESCE(MAX(`Test ID`) + 1, 1) INTO @`Test ID` FROM tests WHERE `Patient ID` = NEW.`Patient ID`;
  SET NEW.`Test ID` = @`Test ID`;
END
$$

MAX関数から始まるトリガーコードの動作。 Nullの最大値はNullであり、Null + 1はNullです。 COALESCE関数は最初のNull以外の値を返すため、Test IDが定義されていない場合は、コンマの後の1になります。 Test IDが値、たとえば1の場合、1 + 1 = 2に1を加えた値を返します。INTO部分は、その値をユーザー変数@Test IDに入れます。最大値は、Patient IDに一致する行でのみ見つかります。この自動インクリメントされた(組み込みではなくコードによって)値は、Test IDNEW値に書き込まれます。

これは私のsampleテーブルの変更されたトリガーです:

delimiter $$
CREATE TRIGGER `insert_sample_auto_inc`
  BEFORE INSERT
  ON `samples`
  FOR EACH ROW

BEGIN
  SELECT COALESCE(MAX(`Sample ID`) + 1, 1) INTO @`Sample ID` FROM samples WHERE `Patient ID` = NEW.`Patient ID` AND `Test ID` = NEW.`Test ID`;
  SET NEW.`Sample ID` = @`Sample ID`;
END
$$

WHEREステートメントを使用してPatient IDTest IDの両方に一致することを除いて、サンプルトリガーでも同じことが起こります。

以下は、この質問が望むように機能するこのサンプルデータベースを作成するために必要なすべてのコマンドです。このコードはMySQL Workbenchを使用して生成されました。

    delimiter $$

CREATE DATABASE `testdb` /*!40100 DEFAULT CHARACTER SET utf8 */$$

delimiter $$

CREATE TABLE `patients` (
  `Patient ID` int(10) unsigned NOT NULL,
  `First Name` varchar(45) DEFAULT NULL,
  `Last Name` varchar(45) DEFAULT NULL,
  `DOB` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`Patient ID`),
  UNIQUE KEY `PatientID_UNIQUE` (`Patient ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$

delimiter $$

CREATE TABLE `tests` (
  `Test ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Patient ID` int(10) unsigned NOT NULL,
  PRIMARY KEY (`Test ID`,`Patient ID`),
  KEY `fk_tests_patient_id_idx` (`Patient ID`),
  CONSTRAINT `fk_tests_patient_id` FOREIGN KEY (`Patient ID`) REFERENCES `patients` (`Patient ID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8$$

CREATE
DEFINER=`root`@`localhost`
TRIGGER `testdb`.`insert_test_auto_inc`
BEFORE INSERT ON `testdb`.`tests`
FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
BEGIN
  SELECT COALESCE(MAX(`Test ID`) + 1, 1) INTO @`Test ID` FROM tests WHERE `Patient ID` = NEW.`Patient ID`;
  SET NEW.`Test ID` = @`Test ID`;
END
$$
delimiter $$

CREATE TABLE `samples` (
  `Sample ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `Test ID` int(10) unsigned NOT NULL,
  `Patient ID` int(10) unsigned NOT NULL,
  `Count Value` int(11) DEFAULT NULL,
  PRIMARY KEY (`Sample ID`,`Test ID`,`Patient ID`),
  KEY `fk_samples_test_id_idx` (`Test ID`),
  KEY `fk_samples_patient_id_idx` (`Patient ID`),
  CONSTRAINT `fk_samples_patient_id` FOREIGN KEY (`Patient ID`) REFERENCES `patients` (`Patient ID`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_samples_test_id` FOREIGN KEY (`Test ID`) REFERENCES `tests` (`Test ID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8$$

CREATE
DEFINER=`root`@`localhost`
TRIGGER `testdb`.`insert_sample_auto_inc`
BEFORE INSERT ON `testdb`.`samples`
FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
BEGIN
  SELECT COALESCE(MAX(`Sample ID`) + 1, 1) INTO @`Sample ID` FROM samples WHERE `Patient ID` = NEW.`Patient ID` AND `Test ID` = NEW.`Test ID`;
  SET NEW.`Sample ID` = @`Sample ID`;
END
$$

delimiter ;
0
altech6983

ケースで参照整合性を強制するために複合キーは必要ありません。その理由は、かなり単純な3層の階層があるためです。

PATIENT 
   +
   |
   ^
 TEST 
   +
   |
   ^
SAMPLE

SAMPLEテーブルにはTESTテーブルへの単純な外部キーが必要であり、TESTテーブルにはPATIENTテーブルへの単純な外部キーが必要です。

これは、サンプルレコードごとにテストレコードが必要であり、テストごとに患者が必要であるため機能します。患者を削除する場合、そのテストはカスケード削除する必要があります。テストを削除する場合は、そのサンプルをカスケード削除する必要があります。したがって、patient_idTESTテーブル内。必要なのは、次のように外部キーのカスケード削除を宣言することだけです...

...
CONSTRAINT 'FK_TEST__PATIENT' FOREIGN KEY ('patient_id')
      REFERENCES 'PATIENT' ('patient_id') ON DELETE CASCADE
...
CONSTRAINT 'FK_SAMPLE__TEST' FOREIGN KEY ('test_id')
      REFERENCES 'TEST' ('test_id') ON DELETE CASCADE
...
5
Joel Brown