JTVT2019現在のデータベース構造

まだまだ refineせねばならないと思いますが、現段階での Database DDLを記録しておきます

 ###############################################################################################
 ### SQL for JTVT2019 
 ### Based on this DDL, the program is constructed.
 ### Programmed by Shigeru SAITO, MD, FACC, FSCAI, FJCC
 ### on March 4th, 2018.
 ### revised on April 12th, 2018
 ###
 ### DB Name : jtvt2019
 ###############################################################################################

CREATE TABLE IF NOT EXISTS `hp_tbls` (
  `id` INT( 11 ) NOT NULL AUTO_INCREMENT,
  `hp_code` VARCHAR( 11 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `hp_name` VARCHAR( 128 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `zip_code` VARCHAR( 7 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `ken_name` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `hp_address` VARCHAR( 256 )CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `country_code` TINYINT( 2 ) NOT NULL DEFAULT '1',			/* Country Code; By using this code , 1: JAPAN*/
                              /* interface such as feet or lb can be aplied. >10: feet/lb */
  PRIMARY KEY (`id`),
  UNIQUE(`hp_code`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `dr_tbls` (
  `id` INT( 11 ) NOT NULL AUTO_INCREMENT,
  `kanji_sirname` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `kanji_firstname` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',	
  `english_sirname` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `english_firstname` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',	
  `hp_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
  `hp_name`  VARCHAR( 128 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
  `job_kind` TINYINT( 2 ) NOT NULL DEFAULT '1',
  `email` VARCHAR( 128 ) NOT NULL DEFAULT '',
  `dr_pwd` VARCHAR( 512 ) NOT NULL DEFAULT '',
  `clue` TINYINT( 1 ) NOT NULL DEFAULT '1',
  `hint` VARCHAR( 512 )NOT NULL DEFAULT '',
  `login_date` DATE NOT NULL DEFAULT '0000-00-00 00:00:00',
  `ip` VARCHAR( 15 ) NOT NULL DEFAULT '000.000.000.000',
  `dr_url` VARCHAR( 60 ) NOT NULL DEFAULT '',
  `is_active` BOOLEAN NOT NULL DEFAULT '0',
  `is_usable` BOOLEAN NOT NULL DEFAULT '1',
  `is_deleted` BOOLEAN NOT NULL DEFAULT '0',
  `created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  `modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  UNIQUE(`email`),
  INDEX(`email`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `login_logs` (
  `id` INT( 11 ) NOT NULL AUTO_INCREMENT,
  `dr_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
  `login_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  `login_ip` VARCHAR( 15 ) NOT NULL DEFAULT '000.000.000.000',
  PRIMARY KEY(`id`),
  INDEX(`dr_tbl_id`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `abstract_tbls` (
  `id` INT( 11 ) NOT NULL AUTO_INCREMENT,
  `hp_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
  `dr_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
  `submission_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  `abstract_topic1` tinyint( 2 ) NOT NULL default '0', /* TAVI, MitraClip, etc  */
  `abstract_topic2` tinyint( 2 ) NOT NULL default '0', /* Complications, etc  */
  `abstract_title` VARCHAR( 200 ) NOT NULL DEFAULT '',
  `abstract_content` VARCHAR( 2000 ) NOT NULL DEFAULT '',
  `is_selected` BOOLEAN NOT NULL DEFAULT '1',
  `is_deleted` BOOLEAN NOT NULL DEFAULT '0',
  `created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  `modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  `last_access_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `time_slot_tbls` (
  `id` INT( 11 ) NOT NULL AUTO_INCREMENT,
  `begin_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
    `end_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',	
  PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `dr_role_tbls` (
  `id` INT( 11 ) NOT NULL AUTO_INCREMENT,
  `dr_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
  `time_slot_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
  `session_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
  `role_kind` tinyint( 2 ) NOT NULL default '0',
  `is_active` BOOLEAN NOT NULL DEFAULT '0',
  `is_usable` BOOLEAN NOT NULL DEFAULT '1',
  `is_deleted` BOOLEAN NOT NULL DEFAULT '0',
  `created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  `modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `session_tbls` (
    `id` INT( 11 ) NOT NULL AUTO_INCREMENT,
  `session_typing_japanese` VARCHAR( 100 ) NOT NULL DEFAULT '',
  `session_typing_english` VARCHAR( 100 ) NOT NULL DEFAULT '',
    `session_sub_title_japanese` VARCHAR( 100 ) NOT NULL DEFAULT '',
  `session_sub_title_english` VARCHAR( 100 ) NOT NULL DEFAULT '',
  `session_begin_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
    `session_end_time` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',	
  `session_objective_japanese` VARCHAR( 300 ) NOT NULL DEFAULT '',
  `session_objective_english` VARCHAR( 300 ) NOT NULL DEFAULT '',
  `is_deleted` BOOLEAN NOT NULL DEFAULT '0',
  `created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  `modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

 

SELECTで選択した列数を PDOで PHPに渡すには

これはしばしば行う間違いなのですが、気が付かないと結構しつこいバグの原因となりますね

$sql = "SELECT COUNT(*) FROM `dr_tbl` WHERE `email` = :email AND `conf_id` = :conf_id;";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(":email", $_SESSION['email'], PDO::PARAM_STR);
$stmt->bindValue(":conf_id", $_SESSION['conf_id'], PDO::PARAM_INT);
$stmt->execute();
    //$rowCount = $stmt->rowCount();
    //echo 'Executed!'.$rowCount.'<br>';
if ($stmt->fetchColumn() > 0) {	// 既に登録されているので弾く
        // この時 fetchColumn()が戻す値は SQL文で得られた count(*)ということになります
        // この結果 SELECT文から正しい件数を知ることができます

 

二日間バグで苦しみ

どうにも納得行かなかったのです それは、http://www.tri-international.orgのサイトをサーバー移行した時に始まったのです

そもそもこちらの都合でサーバー移行したのではありません サーバー運営会社の意向に沿って移行したのです これまでずっと使用してきた Rental Serverは FirstServerだったのですが、それが時代の移り変わりと共に、Zenlogicという次世代のサーバー環境になったのです 正直僕はここら Cloudとか詳しくないので何が違うのか良く分かりません

この移行の時に、これまでの全データも移行したのですが、問題は MySQL Database Server Dataだったのです これも移行したのですが、それと共に phpMyadminという MySQLサーバーデータ管理の秀逸のソフトがそのままでは作動しなくなり、改めてインストール必要でした そしてこの時に、port 3307にインストールされたのです これが問題だったのです

そもそも現在はMySQL5.1が port 3307で作動し、MySQL5.0が port 3306で作動している、という変な状況が続いているのです だいたい port番号なんて普段意識せずに使っているのですよっ

そしてサーバー移行前のデータは MySQL5.0から MySQL5.1に自動的にコピーされ、一見すると同じデータが2つの DB serverにあるのです

さて、PHPプログラムでは Internetアクセスした時には、

$db_host = '127.0.0.1';
//$db_port = '3307';//コメントアウトしているので port3306のまま
$db_user = '**A';
$db_password = '**B';

という風に 普段は port 3306の MySQL databaseに接続しているのです しかし管理ソフトの phpMyadminは port 3307で接続していたのです 当初は同じDBがコピーされていたので、phpMyadminでいくらデータをいらっても これは 3307接続ですから、PHP programからはその変更は見えません

結果的にわけのわからないことになってしまったのです この portの問題に気づくまでには丸一日かかりました そして現在は $db_port = ‘3307’; この一文を活かしているので、全てが port 3307で作動している MySQLでプログラム全体が動いているのです

いやあこのバグは判明にずいぶんかかりました しかし、僕の頭脳が未だ明晰であることが証明されてある意味嬉しいですね

こんな馬鹿なことで1週間潰した

さて、今から本格的にプログラム書こうと思っているのが、2019年に学会長を行うように指示されといるとある学会があるのですが、そのいわゆる学会プログラムやその他諸々を handlingするソフトの開発なのです 当然のことながら Smart Phone/Tablet/PCの全てに対応するように “Responsive Web Design”で開発するのです DBは慣れている MySQLを使用し、言語もこれも慣れている PHPを使用します

こんものいちなり書けないのでテスト・プログラムを作成し、local web serverでテスト繰り返すのですが全く作動しないのです

「えーーっ、なんでぇーーー こんな筈は無いはずだあ」と一週間悩んだのです 少しずつ修正しながらテストするのですが全く僕の意図を無視して動作しないのです

まあこんな感じです

// ここれはフロントエンドで SQLに探索語を渡す Ajax通信のルーチン
    $( document ).ready( function () {
      $( "#search_results" ).slideUp();
      $( "#search_term" ).keyup( function ( e ) {
        e.preventDefault();
        ajax_search();
      } );

      function ajax_search() {
        $( "#search_results" ).show();
        var search_val = $( "#search_term" ).val();
        $.post( "dr_role_find_backend.php", {
          search_term: search_val
        }, function ( data ) {
          if ( data.length > 0 ) {
            $( "#search_results" ).html( data );
          }
        } );
      }
    } );

 

そして受け取る方は、PHPとMySQLです

 session_start();
 session_regenerate_id(true);
 require_once('../utilities/config.php');
 require_once('../utilities/lib.php');	
 charSetUTF8();
 //接続
	try {
   // MySQLサーバへ接続
  	$pdo = new PDO("mysql:host=$db_host;dbname=$db_name_sessions;charset=utf8", $db_user, $db_password);
 // 注意: 不要なspaceを挿入すると' $db_host'のようにみなされ、エラーとなる
 } catch(PDOException $e){
   		die($e-&gt;getMessage());
 }

 $hp_name = strip_tags(trimBothEndSpace(mb_substr($_POST['search_term'], 0, 100)));	// 前後のspaceなど削除し、文字数を100文字に制限する
 $hp_name = strtoupper(mb_convert_kana($hp_name, 'ashK'));		// 半角英字大文字に変換する

 $stmt = $pdo-&gt;prepare("SELECT * FROM `hp_tbls` WHERE `hp_name` LIKE :hp_name ORDER BY `hp_name` ASC;");
 $stmt-&gt;bindValue(":hp_name", '%'.$hp_name.'%', PDO::PARAM_STR);
 $flag = $stmt-&gt;execute();
 $rows = $stmt-&gt;fetchAll(PDO::FETCH_ASSOC);
 
 if (!$flag) {
   		$infor = $stmt-&gt;errorInfo();
     exit($infor[2]);
 }

 

これで、検索語として病院名の一部を入力すれば、DBより検索してくれる筈なのです

しかし、しかし動作しない 本当にこの解決に一週間かかり、先程やっと解決しました

色々な問題があったのです まずは

trimBothEndSpace(mb_substr($_POST['search_term'], 0, 100))

という関数ですが、(1) mb_substrの引数を何時の間にか消去してました つぎに(2) trimBothEndSpaceという関数ですが、これは自作関数なのですが、それをlib.phpに作成してあり(ある筈)、それを読み込んで使用するのですが、何と lib.phpの中にこの関数を書いていなかったのです

この2つのバグのために、phpそのものが走らず結果的に echoで途中経過を出そうと思っても出せない そんな事態に陥っていたのです 本当に大変なバグ退治でした これも Ajax通信によるプログラムだからのことです 本当に非同期通信というのは難しいです これが解決してうまく動作しているデモ画面です

うまく Ajax通信が動作しているところ

あけましてお目出度うございます

2018年新年最初の up ですね

昨日3日夕方の飛行機で札幌に入りました 本日から早速TAVIとなります この間、RAP and BEAT II臨床試験のためのデータベースを作成していました もっとも、2年前に行った RAP and BEAT国際臨床試験のデータベースを改変するだけですので、それほどの工程になるとは見込んでいません どうせならば、この2年間の Web技術の変化に併せて、Bootstrap4.0や jQuery3.0を取り込みたいと思うのですが、ここいらへんはテストせねば何とも言えませんね

まずは DDL (Data Definition Language)でデータ構造を見直しました とりあえずここまで見直しました

 ###############################################################################################
 ### SQL for RAP and BEAT II Trial Version 1.0  
 ### Based on this DDL, the program is constructed.
 ### Programmed by Shigeru SAITO, MD, FACC, FSCAI, FJCC
 ### on January 4th, 2018.
 ###############################################################################################

CREATE TABLE IF NOT EXISTS `hp_tbls` (
	`id` INT( 11 ) NOT NULL AUTO_INCREMENT,
	`hp_name` VARCHAR( 128 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
	`hp_login_name` VARCHAR( 32 ) UNIQUE NOT NULL DEFAULT '',
	`hp_pwd` VARCHAR( 32 ) NOT NULL DEFAULT '',
	`hp_dr_email_in_charge` VARCHAR( 128 ) NOT NULL DEFAULT '',
	`hp_address` VARCHAR( 256 )CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
	`is_active_hp` BOOLEAN NOT NULL DEFAULT '0',
	`is_usable_hp` BOOLEAN NOT NULL DEFAULT '1',
	`is_deleted_hp` BOOLEAN NOT NULL DEFAULT '0',
	`country_code` TINYINT(2) NOT NULL DEFAULT '1',			/* Country Code; By using this code , 1: JAPAN*/
															/* interface such as feet or lb can be aplied. >10: feet/lb */
	`random_index` INT( 11 ) NOT NULL DEFAULT '0',
	`is_created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
	PRIMARY KEY (`id`),
	UNIQUE(`hp_name`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `dr_tbls` (
	`id` INT( 11 ) NOT NULL AUTO_INCREMENT,
	`sirname` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
	`firstname` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',	
	`is_male` BOOLEAN NOT NULL DEFAULT '1',
	`birth_year` DATE NOT NULL DEFAULT '0000-00-00',
	`hp_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
	`job_kind` TINYINT( 2 ) NOT NULL DEFAULT '1',
	`email` VARCHAR( 128 ) NOT NULL DEFAULT '',
	`dr_pwd` VARCHAR( 512 ) NOT NULL DEFAULT '',
	`clue` TINYINT( 1 ) NOT NULL DEFAULT '1',
	`hINT` VARCHAR( 512 )NOT NULL DEFAULT '',
	`created` DATE NOT NULL DEFAULT '0000-00-00 00:00:00',
	`login_date` DATE NOT NULL DEFAULT '0000-00-00 00:00:00',
	`ip` VARCHAR(15) NOT NULL DEFAULT '000.000.000.000',
	`dr_url` VARCHAR(60) NOT NULL DEFAULT '',
	`is_active` BOOLEAN NOT NULL DEFAULT '0',
	`is_usable` BOOLEAN NOT NULL DEFAULT '1',
	`is_deleted` BOOLEAN NOT NULL DEFAULT '0',
	`is_pi` BOOLEAN NOT NULL DEFAULT '0',
	`is_created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
	`modified` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
	PRIMARY KEY (`id`),
	UNIQUE(`email`),
	INDEX(`email`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `login_logs` (
	`id` INT( 11 ) NOT NULL AUTO_INCREMENT,
	`dr_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
	`login_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
	`login_ip` VARCHAR( 15 ) NOT NULL DEFAULT '000.000.000.000',
	PRIMARY KEY(`id`),
	INDEX(`dr_tbl_id`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `pt_tbls` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `hp_tbl_id` INT(11) NOT NULL DEFAULT '0',
  `registration_dr_id` INT(11) NOT NULL DEFAULT '0',
  `registration_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  `arbitrary_id` VARCHAR(20) NOT NULL DEFAULT '',
  `is_consent` BOOLEAN NOT NULL DEFAULT '0',
  `consent_date` DATE NOT NULL DEFAULT '0000-00-00',
  `is_dra` BOOLEAN NOT NULL DEFAULT '0',		/* 0: ConventionalRadial Approach */
  														/* 1: Distal Radial Approach */
  ###############################################################################################
  ######################### Beginnin of Screen (1) Case Registration #########################
  ###############################################################################################
  `age` INT(3) NOT NULL DEFAULT '0',					/* Age in year */
  `is_male` TINYINT(1) NOT NULL DEFAULT '1',			/* 0: female, 1: male */
  `bh` INT(3) NOT NULL DEFAULT '0',						/* body height in CM */
  `bw` FLOAT(4,1) NOT NULL DEFAULT '0',					/* body weight in Kg */
  `is_dm` BOOLEAN NOT NULL DEFAULT '0',				/* 0: no diabetes, 1: NIDDM, 2: IDDM */
  `is_ht` BOOLEAN NOT NULL DEFAULT '0',				/* 0: not hypertensive, 1: hypertensive */
  `is_hl` BOOLEAN NOT NULL DEFAULT '0',				/* 0: not dyslipidemic, 1: dyslipidemic */
  `is_hu` BOOLEAN NOT NULL DEFAULT '0',				/* 0: not hyperuricemic, 1: hyperuricemic */
  `is_sm` BOOLEAN NOT NULL DEFAULT '0',				/* 0: not smoker at all, 1: Ex-smoker, 2: Current Smoker */
  `is_fhx` BOOLEAN NOT NULL DEFAULT '0',				/* 0: no family history of ischemic heart disease, 1: positive family history of IHD */
  `ckd` INT(2) NOT NULL DEFAULT '0',				/* 0: no CKD, 1: Stage I Protein+ GFR>=90, 2: Stage II Protein+ GFR>=60 */
  														/* 3: Stage III GFR>=30, 4: Stage IV GFR>=15, 5: Stage V Renal Failure */
  `is_cva` BOOLEAN NOT NULL DEFAULT '0',				/* 0: no CerebroVascular Accident, 1: CVA+ */
  `is_pad` BOOLEAN NOT NULL DEFAULT '0',				/* 0: no Peripheral Vascular Disease, 1: PAD+ */
  `hx_of_omi` BOOLEAN NOT NULL DEFAULT '0',			/* 0: no history of previous old myocardial infarction, 1: history of OMI+ */
  `hx_of_pci` BOOLEAN NOT NULL DEFAULT '0',			/* 0: no history of previous PCI, 1: history of PCI+ */
  `hx_of_cabg` BOOLEAN NOT NULL DEFAULT '0',			/* 0: no history of previous coronary bypass surgery, 1: history of CABG+ */
  `hx_of_heart_d` BOOLEAN NOT NULL DEFAULT '0',		/* 0: no history of any heart disease, 1: history of any heart disease+ */
  `comorbidity` TEXT NOT NULL,							/* Any free TEXT */
  `is_scr1_complete` BOOLEAN NOT NULL DEFAULT '0',	/* Screen (1) is alredy registered? 0: not, 1: finished */
  ###############################################################################################
  ######################### Beginnin of Screen (2) Lab_Cathe #########################
  ###############################################################################################
  `rbc` INT(3) NOT NULL DEFAULT '0',					/* RBC x 10^4 */
  `hb` FLOAT(3,1) NOT NULL DEFAULT '0.0',				/* Hemoglobin g/dl */
  `pl` FLOAT(4,1) NOT NULL DEFAULT '0.0',				/* Platelet x 10^4 */
  `cre` FLOAT(3,1) NOT NULL DEFAULT '0.0',				/* Creatinine mg/dl */
  `is_aspirin` BOOLEAN NOT NULL DEFAULT '1',			/* 0: no aspirin, 1: with aspirin */
  `is_thieno` BOOLEAN NOT NULL DEFAULT '1',			/* 0: no thienopyridine, 1: with */
  `is_p2y12` BOOLEAN NOT NULL DEFAULT '0',			/* 0: no p2y12 inhibitor, 1: with */
  `is_warfalin` BOOLEAN NOT NULL DEFAULT '0',		/* 0: no worfalin, 1: with */
  `is_heparin` BOOLEAN NOT NULL DEFAULT '1',			/* 0: no heparin, 1: with heparin */
  `is_2b3a` BOOLEAN NOT NULL DEFAULT '0',			/* 0: no IIb/IIIa antagnonist, 1: with IIb/IIIa antagnonist */
  `biggest_cath_size` TINYINT(1) NOT NULL DEFAULT '0',	/* 1: 4Fr, 2: 5Fr, 3: 6Fr */
  `is_pci` BOOLEAN NOT NULL DEFAULT '0',				/* 0: diagnostic only, 1: going to PCI */
  `assigned_artery_success` BOOLEAN NOT NULL DEFAULT '0', /* 0: success, 1: failed */
  `final_access_artery` TINYINT(1) NOT NULL DEFAULT '0',	/* 0: right CRA, 1: right DRA, 2: left CRA, 3: left DRA, 4: extra-radial */
  `is_prev_puncture` BOOLEAN NOT NULL DEFAULT '0',	/* 0: no previous puncture of the final access side radial argery */
  														/* 1: previous history of puncture */
  `hitting_ra_times` INT(2) NOT NULL DEFAULT '1',			/* How many hitting of radial artery to successful cannulation */
  														/* 10: failed puncture */
  `spasm` BOOLEAN NOT NULL DEFAULT '0',				/* Spasm during whole procedure 0: nothing, 1: any spasm */
  `arterial_cannulation_time` INT(3) NOT NULL DEFAULT '0',			/* Local to successful arterial cannulation in minutes */
  `proc_time` INT(3) NOT NULL DEFAULT '0',				/* Total procedure time in minutes */
  `radiation` INT(4) NOT NULL DEFAULT '0',				/* Total radiation dose in mGy */
  `contrast` INT(4) NOT NULL DEFAULT '0',				/* Total contrast dye volume in ml */
  `puncture_pain` INT (2) NOT NULL DEFAULT '0',					/* Pain score between 0 and 3, none, slight, much, extreme */
  `is_scr2_complete` BOOLEAN NOT NULL DEFAULT '0',	/* Screen (2) is alredy registered? 0: not, 1: finished */
  ###############################################################################################
  ######################### Beginnin of Screen (3) Outcomes #########################
  ###############################################################################################
  `hemostasis_pain` INT (2) NOT NULL DEFAULT '0',					/* Pain score between 0 and 3, none, slight, much, extreme */
  `to_hemostasis_minutes` INT( 3 ) NOT NULL DEFAULT '0',	/* hemostasis time in minutes to final hemostasis */
  `rao_discharge` BOOLEAN NOT NULL DEFAULT '0',		/* Radial Artery Occlusion at discharge 0: patent, 1: occluded */
  `barc_bleeding` INT(2) NOT NULL DEFAULT '0',		/* Puncture Site Bleeding at dischage */
  														/* 0: type 0, 1: type 1, 2: type 2, 3: type 3a, 4: type 3b, 5 type 3c, 6: type 4, 7: type 5a, 8: type 5b */ 
  `pro_succ` BOOLEAN NOT NULL DEFAULT '1',			/* Procedure Success of Index Procedure (PCI or CAG) 0: failed, 1: succeeded */
  `hand_function` INT(2) NOT NULL DEFAULT '0',	/* 0: no disability, 1: minor disability, 2: moderate disability, 3: need help */
  `any_comment` TEXT NOT NULL, 								/* Any TEXT message */
  `is_anomaly` BOOLEAN NOT NULL DEFAULT '0',	/* if radial artery has anomaly or narrowing, set to 1 */
  `anomaly_comment` TEXT NOT NULL, 		/* describe anomaly */
  `is_scr3_complete` BOOLEAN NOT NULL DEFAULT '0' ,	/* Screen (3) is alredy registered? 0: not, 1: finished */
  ###############################################################################################
  ######################### End of Screen (3) of Case Registration #########################
  ###############################################################################################
  `is_deleted` BOOLEAN NOT NULL DEFAULT '0',
  `is_finalized` BOOLEAN NOT NULL DEFAULT '0',
  `finalized_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  `last_access_dr` INT(11) NOT NULL DEFAULT '0',
  `finalized_dr`  INT(11) NOT NULL DEFAULT '0',
  `is_created` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  `last_access_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY  (`id`),
  UNIQUE(`arbitrary_id`),
  KEY `hp_tbl_id` (`hp_tbl_id`),
  KEY `registration_dr_id` (`registration_dr_id`),
  INDEX (`last_access_dr`),
  INDEX (`arbitrary_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `pt_access_log` (
	`id` INT( 11 ) NOT NULL AUTO_INCREMENT,
	`pt_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
	`access_dr_id` INT( 11 ) NOT NULL DEFAULT '0',
	`access_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
	`access_ip` VARCHAR( 15 ) NOT NULL DEFAULT '000.000.000.000',
	PRIMARY KEY (`id`),	
	INDEX(`pt_tbl_id`),
	INDEX(`access_dr_id`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE IF NOT EXISTS `random_tbls` (
	`id` INT( 11 ) NOT NULL AUTO_INCREMENT,
	`dra_or_cra` TINYINT( 1 ) NOT NULL DEFAULT '0',		/* 0: randomized to DRA, 1: randomized to CRA */
	PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

これからプログラムの修正にとりかかります

馬鹿なことをやっていた 今気づいたけど

さて、kamakuralive.netは鎌倉ライブの Home Pageですが、先日までサーバーの切り替えですったもんだしたのです しかし、このクラウド・ベースのサーバーになり速度は明らかに早くなり安定しています

ここのプログラムは何回も言いますが、全てゼロから僕自身が html, css, jQuery, javascript, php, sql (mysql)を用いてプログラムを書いてきたものです

基本的にデータ構造は、たった3つのテーブルを使用するのみです それは、それぞれ dr_tbl, session_tbl, role_tblと名付けていますが、論理的にはお互いにリンク付けられ、関係データベースを形成しています

そのように作ったつもりだったのですが、今日突然気づきました それは database sqlのデバグをしている段階だったのです 何と role_tblsが session_tblを指すべき indexを作っていなかったのです!!!

もちろん今からこれを作るのは簡単ですが、そうなるとそこに関係したプログラムのみならず、既に入力されているデータそのものも変更が必要となります 参りました

そんなことをすれば膨大な時間がかかりますので、とりあえずはこのままにすることに決めました ほとんど不都合は発生しませんが、役割の時間帯重複を sqlで検出することが困難なのです

三つのテーブルをつなぐ肝腎の SQL文

忘れない内に残しておきましょう というのも、インターネット上には誤った SQL文が堂々と upload公開されていたりするのですから・・・

まずはテーブルの定義です

CREATE TABLE `man_tbls` (
	`id` INT( 11 ) NOT NULL AUTO_INCREMENT,
	`sirname` VARCHAR( 100 ) NOT NULL DEFAULT '',
	`firstname` VARCHAR( 100 ) NOT NULL DEFAULT '',
	`is_male` BOOLEAN NOT NULL DEFAULT '1',
	`birthdate` DATE NOT NULL DEFAULT '0000-00-00',
	PRIMARY KEY (`id`),
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE `disease_tbls` (
	`id` INT( 11 ) NOT NULL AUTO_INCREMENT,
	`diagnosis` VARCHAR( 100 ) NOT NULL DEFAULT '',
	PRIMARY KEY (`id`),
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

CREATE TABLE `relation_tbls` (
	`id` INT( 11 ) NOT NULL AUTO_INCREMENT,
	`man_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
        `disease_tbl_id` INT( 11 ) NOT NULL DEFAULT '0',
	PRIMARY KEY (`id`),
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci AUTO_INCREMENT=0;

この SQL文により、MySQLデータベース・エンジンにより三つのテーブルが作成されます 本当はこのデータベースに対して、さっき記述したデータを入力しておいて下さると助かりますが・・・

さて、このようなデータベース、これは実は 二つの固有テーブルを「関係テーブル」で結びつける「多」対「多」関係のデータなのですが、この中から、ある人が、ある病気にかかっている、ということを記述する SQL文は次のようになります

SELECT `M`.`id`,  `M`.`sirname`, `M`.`firstname`, `M`.`is_male`, `M`.`birthdate`,`D`.`disease
FROM `man_tbls` AS `M` INNER JOIN(`relation_tbls` AS `R` INNER JOIN  `disease_tbls` AS `D` ON `D`.`id` = 
`R`.`disease_tbl_id`  ) ON `M`.`id` = `R`.`man_tbl_id`;

結構複雑でしょ?

少し複雑な SQL文

一泊二日で台湾・高雄でお仕事して月曜日は外来診療、そして色々なお仕事しました

火曜日の9:27は朝から Houstonに向けて飛び立ち、そのまま Colombiaに入るのです 今は、Houston空港で 6時間余りの transitをしています

そんな中懸案の SQLがようやく書けました これは、三つのテーブルを結びつけるものですが、要するに「多」対「多」という二つのテーブルを結びつけるために、間に「関連」テーブルを使うものです

この関係は実社会で良く見られるものです 例えば 人物テーブルを考えて下さい、このテーブルで重要なデータは

  1. 固有のID 今日の日本であれば、「個人番号」でしょうね
  2. 名前の姓
  3. 名前の名
  4. 性別
  5. 生年月日

などでしょう もちろん他にも色々付け足せますが、ここで重要なのは個々のフィールド (ここでは番号の1~5ですが)については、一度値が入れば、変化しない、ということです そして、1については、「個人番号」がそうであるように、重複することが決して無い ということなのですよっ

例えば、6.として「職業」を持ってきたとします ある時点では、その値は、学生であり、次には会社員となり、その次にはアルバイトになるかも知れません 要するに、「職業」というものは変化していきますので、この人物テーブルの構成要素としては相応しくありません

もちろん、「職業1」「職業2」「職業3」・・・・「職業10」ぐらい予備に造っておけばそれでも良いでしょうが

名前については、実は微妙な問題があります 日本では結婚することにより女性の姓が変化するのが普通ですので、最初から「姓1」「姓2」・・「姓5」ぐらい造っておいた方が良いかも知れませんね

さて、次に 病気テーブル について考えましょう これは簡単に次のようにしましょう

  1. 病気のID ここは例えば色々な国際的コードがあります
  2. 病名 例えば、胃炎、心筋梗塞などなどですね

さて、この二つのテーブルを用いて、ある人がある病気にかかっている という状態をどのように表せば良いでしょうか?

実はここで必要なのが、二つのテーブルを結びつける「関係テーブル」なのです

まずは「人物テーブル」です

ID 性別 生年月日
1 ABE SHI M 19500215
2 TABE SHISHI F 19511115
3 TABEKI MOMO M 19520415

さて次に「病気テーブル」です

ID 病名
1 急性胃炎
2 慢性胃炎
3 狭心症

さて、ある人の状態を表すにはどのようにすれば良いでしょうか? 例えば TABEさんが狭心症にかかっている、というのは「人物テーブル」のID=1と 「病気テーブル」のID3を結びつければ良いですよね 従って以下の 関連テーブルが必要となります

ID 人物テーブルID 病気テーブルID
1 1 3

このテーブルをどんどん増やしていけば良いのですよね これが Relational Database (関係データベース)の基礎の基礎なのですが、結構難しいのですよ これをSQL文で書くのは

何と そうだったのか

ここに二つのテーブルがあります そう、片方は doctor_tblsであり、今一つは role_tblsです 簡単にすれば

doctor_tblsは

doctor_tbl_id name is_male
1 saito 1
2 shigeru 1
3 hanako 0

このようにしましょう is_maleは性別であり、男性であれば、1 女性であれば 0としましょう

もう一つのテーブルは役割配置表 role_tblsで その構造は

role_tbl_id doctor_tbl_id role_kind
1 2 chair
2 2 speaker
3 1 moderator

のように例えばなります つまり、saitoさんは doctor_tbl_id = 1ですが、 role表の中の role_tbl_id = 3に配置されていますね そして役割は moderatorということになります これをSQL文で記述すれば

SELECT * FROM `doctor_tbls` INNER JOIN `role_tbls` 
ON `doctor_tbls`.`doctor_tbl_id` = `role_tbls`.`doctor_tbl_id`;

ということになります ここで良くあるように

role_tbl_id doctor_tbl_id role_kind
1 2 chair
2 2 speaker
3 1 moderator
4 1 speaker
5 1 chair

のようにsaitoさんの役割分担が三つに増えたとしましょう この時に、役割が2つの人を探す SQL文について考えみました なかなか正解には至らなかったのですが、色々調べてようやく分かりました それは

SELECT `dr_tbl_id`, count(`dr_tbl_id`) as `Frequency` FROM `role_tbls` group by `dr_tbl_id` HAVING `Frequency` = '2'

というものです ここで HAVING句を用いるのと、仮想列名 Frequencyというのを用いるのがミソなのです 素晴らしいですね

とにかく SQLというのはプログラミング言語の中でも異色のものであり、集合演算をするのです これを理解しないと無駄足を踏むことになりますね

目標としていた9月1日に何とか間に合いました

鎌倉ライブデモンストレーションのHome Pageの全面改訂を8月の10日頃から行ってきました ある程度公開するのを9月1日と目標設定していたのですが、何とか間に合いました

http://kamakuralive.net/

大きなバグはとれていると思います このページの特徴は、SQL databaseに色々なデータを別の保護されたページにより登録すれば、それが自動的にこのページで更新されていく、ということです

鎌倉ライブデモンストレーションの詳細については未だ確定できない部分も多く、かといって全く分からないままで放置しておくことも良くないので、このような構造にしたのです

僕にとってこれは長年のライブデモンストレーション生活の中での最適解の一つなのですが、それをどのように実現していけば良いのか、それを解決できるだけのスキルも知力も以前の僕にはありませんでした しかし、今は違います これをやり遂げるだけの能力を習得したのです 嬉しいな

これもTAVIがすんなりと治療できるから可能なのです ありがとう SAPIEN3