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

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

洗練化するデータ構造

鎌倉ライブデモンストレーションの公式Web Site構築中です こっそりと現在の姿お見せすると

http://kamakuralive.net/23rd/db_read/come_session_all_read.php

となるのですが、もちろん公式には未だ公開していません

このページの特徴は、参加して頂く方のデータを別のページでdatabaseに登録し、そこから読みだしているのです 従ってそのページにアクセスする方々は、常時データを更新することができ、それが瞬時に反映される、ということなのです さらに、データ構造を工夫してあり、たとえば ◯◯さんがどの時間帯に dutyがあり、それがぶつかっていないかどうかもすぐに判明できる、というものにしてあるのです このデータ構造を創造するのには随分と頭を回転させました 知力の勝負ですね

ぎりぎりセーフでお礼メールの発送完了 そして新年に

大晦日の紅白歌合戦が始まってから、「これはいかん」と思いま、集中的にとりかかりました

それは、鎌倉ライブデモンストレーションにFacultyとしていらして頂いた先生方にお礼のメールを出すことです もちろんそんなことは手作業でもできるのですが、折角ですのでプログラムを書いて Databaseより宛先を拾い、そしてその宛先にメールを発信する、そうしようと思いました

時間は迫るし、何しろプログラミングも少し離れると忘れてしまうので回復に時間が必要でした それでもぎりぎり 11:59PMには全員に自動発信することができました

良かった良かった そして新年となり、「皆様方 新年も宜しくお願いします。」

夢は広がる

さて、先ほどの SQLを使用すればたとえば以下のような出力が得られます もちろんデータは dummyですし、<table></table>を用いてhtmlで整形しています

登録数 病院名 年月
3 ShonanKamakura General Hospital 202410
15 ShonanKamakura General Hospital 202411
22 ShonanKamakura General Hospital 202412

これを用いれば、データをデータベースより出力し、現在勉強中の d3.jsを用いてグラフ化することも近いですね これは夢が拡がります

本日また新たな手技に一歩を踏み出すのです

今朝は早朝起床し、何時もより長く小雨降りしきる中自転車で出勤しました わざと通り道してペダルを漕ぎ、何だか何時もうまくいかない世の中を嘆きながら心を清く、そして強くしていくのでした

とはいいつつ頭の中は高速回転で一つのことを考えていたのです それは、登録日、病院毎に登録症例数を一覧として出力する SQL文の作成でした これは実用上重要であり、もちろん PHPや JavaScriptなどのスクリプトを介すれば誰でも出来ますが、それを SQL文で一発で行う、というものです

そして書きましたね 以下の文を

SELECT 
COUNT(*), `hp_tbls`.`hp_name`,       DATE_FORMAT(`pt_tbls`.`registration_date`, '%Y%m') 
FROM `pt_tbls` 
INNER JOIN `hp_tbls` 
ON `pt_tbls`.`hp_tbl_id` = `hp_tbls`.`id` 
GROUP BY `hp_tbls`.`id`, DATE_FORMAT(`pt_tbls`.`registration_date`, '%Y%m')

これで病院別かつ月別に登録症例数が一覧として出力されます あっ、SQLは MySQLのものですよ ここでのキモは、GROUP BYと DATE_FORMATでしょうか

何れにしても早朝より頭の回転は優れていました これで本日の新しい手技に全力で臨めますね