現在、ubuntu からネットワーク上にある windows 7 の sqlserver 内にある検査データベース(LAPIS 3)にアクセスして必要なデータを ubuntu の sqlite3 に書き写してそれを閲覧しています。
ところが最近ちょっとしたエラーを経験しました。
一部、データが表示されなくなったのです。

上の図で、2021-12-25 の蛋白半定の部分には「1+」という表示がされなければなりませんがここでは表示されていません。
しかしその日のデータを見るとデータとしては存在しているようです。
どういうこと?
詳しく調べてみると、項目名が 2010 年と 2021 年で変わってしまっていることがわかりました。
私の作ったプログラムは php と jquery を使っているのですが、php から抽出結果を配列で jquery に渡してほとんどを jquery で処理するようになっています。
横軸は日付で縦軸は項目名、一つ一つのデータを日付と項目名で座標を探して書き込むようになっており、「蛋白半定」が現在では「尿蛋白」となっているため、データが宙に浮いてしまったのです。
「蛋白半定」と「尿蛋白」はいずれも項目番号 109 なので項目番号で表を作成し、その後で項目番号を項目名に変更すればいいのですが、jquery は作った本人の私が見てもよくわからないコードであり、いっそのことほとんどを php で作ろうと思いました。
全体的な流れ
以下のようにします。
- カルテ番号から患者氏名検索
- カルテ番号から全データを取得
- データがセットされていない項目を削除
- 検査の日付と項目番号の配列作成
- 検査項目名を読み込む
- 表示用のシートを初期化
- 表示用のシート作成
- 判定用テーブルの初期化
- 判定用テーブル作成
- 表示用シートの表示
カルテ番号から患者氏名検索
public function pName( $karteNo ) // カルテ番号から氏名
{
$ptName = $this -> ptName ;
try{
$pdo = new PDO('sqlite:db/lapis.sql3','' ,'' ,array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$sql = "SELECT name FROM kensa WHERE karteNo = ? ORDER BY hizuke DESC LIMIT 1 ;";
$stmt = $pdo -> prepare($sql);
$stmt -> execute(array( $karteNo ));
$row = $stmt->fetch();
$ptName = $row['name'] ;
$this -> ptName = $ptName;
}catch (PDOException $e){
echo('Error:'.$e->getMessage());
die();
}
}
カルテ番号から全データを取得
public function kekka( $karteNo ) // カルテ番号から検査結果
{
try{
$pdo = new PDO('sqlite:db/lapis.sql3','' ,'' ,array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$sql = "SELECT hizuke, koumokuNo, Kekka, KijyunMin, KijyunMax FROM kekka WHERE (hizuke, uketukeNo) IN (SELECT hizuke, uketukeNo FROM kensa WHERE karteNo = ?) ORDER BY hizuke DESC;";
$stmt = $pdo->prepare($sql);
$stmt->execute(array( $karteNo ));
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$kekkaArr[] = array($row['hizuke'], $row['koumokuNo'], $row['Kekka'], $row['KijyunMin'], $row['KijyunMax']) ;
}
$this -> kekkaArr = $kekkaArr ;
}catch (PDOException $e){
echo('Error:'.$e->getMessage());
die();
}
}
hizuke でインデックスを作成してあり、サブクエリで「order by hizuke desc」で抽出するとこれまでの 10 分の 1 で抽出できることがわかりました。
データがセットされていない項目を削除
public function deleteNull() // 結果が null を削除
{
$kekkaArr = $this -> kekkaArr ;
$temp = $this -> temp ;
foreach( $kekkaArr as $eachline )
{
if( $eachline[2] != null ) {
$temp[] = $eachline ;
}
}
$this -> kekkaArr = $temp ;
}
検査の日付と項目番号の配列作成
public function hkArr() // 日付と項目番号を重複なしで配列化してソート
{
$kekkaArr = $this -> kekkaArr ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
foreach( $kekkaArr as $eachline )
{
if( !in_array( $eachline[0], $hizukeArr ) ){
$hizukeArr[] = $eachline[0] ;
}
if( !in_array( $eachline[1], $koumokuNoArr ) ){
$koumokuNoArr[] = $eachline[1] ;
}
}
rsort( $hizukeArr );
sort( $koumokuNoArr );
$this -> hizukeArr = $hizukeArr ;
$this -> koumokuNoArr = $koumokuNoArr ;
}
検査項目名を読み込む
public function koumokuName() // koumokuMST から検査項目番号と検査項目名の対応表作成
{
$koumokuNameArr = $this -> koumokuNameArr ;
try{
$pdo = new PDO('sqlite:db/lapis.sql3','' ,'' ,array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$sql = "SELECT koumokuNo, koumokuName FROM koumokuMST ;";
$stmt = $pdo->prepare($sql);
$stmt->execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$koumokuNameArr[] = array( $row['koumokuNo'], $row['koumokuName'] ) ;
}
$this -> koumokuNameArr = $koumokuNameArr ;
}catch (PDOException $e){
echo('Error:'.$e->getMessage());
die();
}
}
表示用のシートを初期化
public function initTbl() // 最終的なテーブルを初期化しておく
{
$tableData = $this -> tableData ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
$gyo = count($koumokuNoArr) ;
$retu = count($hizukeArr) ;
for( $i=0; $i < $gyo; $i++) {
for( $j=0; $j < $retu; $j++) {
$tableData[$i][$j] = null ;
}
}
$this -> tableData = $tableData ;
}
表示用のシート作成
public function createSheet() // 日付と項目番号で検索して検査結果を書き込んでいく
{
$kekkaArr = $this -> kekkaArr ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
$tableData = $this -> tableData ;
foreach( $kekkaArr as $eachline ){
$hizuke = $eachline[0] ;
$koumokuNo = $eachline[1] ;
$eachData = $eachline[2] ;
$xkey = array_search( $hizuke, $hizukeArr );
$ykey = array_search( $koumokuNo, $koumokuNoArr );
$tableData[$ykey][$xkey] = $eachData ;
}
$this -> tableData = $tableData ;
}
判定用テーブルの初期化
public function initHantei() // 判定テーブルの初期化
{
$kekkaHantei = $this -> kekkaHantei ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
$gyo = count($koumokuNoArr) ;
$retu = count($hizukeArr) ;
for( $i=0; $i < $gyo; $i++) {
for( $j=0; $j < $retu; $j++) {
$kekkaHantei[$i][$j] = null ;
}
}
$this -> kekkaHantei = $kekkaHantei ;
}
判定用テーブル作成
public function hantei()
{
$kekkaArr = $this -> kekkaArr ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
$kekkaHantei = $this -> kekkaHantei ;
foreach( $kekkaArr as $eachline )
{
$hizuke = $eachline[0] ;
$koumokuNo = $eachline[1] ;
$kekka = $eachline[2] ;
$min = $eachline[3] ;
$max = $eachline[4] ;
$xkey = array_search( $hizuke, $hizukeArr );
$ykey = array_search( $koumokuNo, $koumokuNoArr );
if( $kekka < $min ) {
$kekkaHantei[$ykey][$xkey] = "low" ;
}elseif( $kekka > $max ) {
$kekkaHantei[$ykey][$xkey] = "high" ;
}
}
$this -> kekkaHantei = $kekkaHantei ;
}
表示用シートの表示
public function createTable() // 出力するテーブルを作成
{
$tableData = $this -> tableData ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
$koumokuNameArr = $this -> koumokuNameArr ;
$kekkaHantei = $this -> kekkaHantei ;
$ptName = $this -> ptName ;
$lineNum = 0 ;
echo "<p>$ptName<input type='button' value='印刷' class='print'></p>" ;
$tbl = "<table _fixedhead='rows:1; cols:1;'>\n";
//----------------- 一番上の行を追加 -- 日付の行
array_unshift( $hizukeArr, "項目" ); // 項目のカラムを追加
$header = "" ;
foreach( $hizukeArr as $key => $hizuke )
{
if( $key === 0 )
{
$eh = $hizuke ;
}else{
$eh = date( "Y-m-d", strtotime($hizuke)) ;
}
$header .= "<th>$eh</th>" ;
}
$tbl .= "<tr>{$header}</tr>\n" ;
//------------------ 各データ行を追加
foreach( $tableData as $rkey => $eachline )
{
$searchkey = array_search( $koumokuNoArr[$lineNum], array_column( $koumokuNameArr, 0));
$koumokuName = $koumokuNameArr[$searchkey][1] ;
$datas = "" ;
foreach( $eachline as $ckey => $val )
{
$hantei = $kekkaHantei[$rkey][$ckey] ;
if( $hantei === 'high') {
$datas .= "<td class='high'>$val</td>";
}elseif( $hantei === 'low' ) {
$datas .= "<td class='low'>$val</td>";
}else{
$datas .= "<td>$val</td>";
}
}
$tbl .= "<tr><th class='koumoku'>$koumokuName</th>$datas</tr>\n" ;
$lineNum++ ;
}
$tbl .= "</table>" ;
echo "<div class='container'>{$tbl}</div>" ;
}
ポイント
基本となる一つ一つのデータは以下のような感じです。

これを配列に格納して、以下のようなテーブルに一つ一つ書き込んでいきます。

さらにその値が正常上限より上か、正常下限より下か、正常範囲内かを判定する配列を作成して、表示する最後の段階で判定に応じてclass を設定し css で色分けします。
全体のプログラム
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="CSS/style.css" type="text/css" />
<script src="js/jquery-3.2.1.min.js"></script>
<script src='js/fixed_midashi.js'></script>
<script type="text/javascript">
$(function(){
$(".print").click(function(){
location.href = "printAll.php?karteNo=" + karteNo ;
});
});
</script>
<style type="text/css">
.container {width: 1200px;}
td.odd{background-color: #f7f7f7;}
td.high{color:red;}
td.low{color:blue;}
.print{background-color: orange;font-size: 15px;margin-left: 800px;}
</style>
</head>
<body onLoad="onLoadActions();">
<?php
class dataKarte {
private $ptName ;
private $kekkaArr ;
private $koumokuNoArr ;
private $koumokuNamearr ;
private $temp ;
private $hizukeArr;
private $tableData;
private $kekkaHantei ;
public function __construct()
{
$this -> ptName = "";
$this -> kekkaArr = array();
$this -> koumokuNoArr = array();
$this -> koumokuNameArr = array();
$this -> temp = array();
$this -> hizukeArr = array();
$this -> tableData = array();
$this -> kekkaHantei = array();
}
public function pName( $karteNo ) // カルテ番号から氏名
{
$ptName = $this -> ptName ;
try{
$pdo = new PDO('sqlite:db/lapis.sql3','' ,'' ,array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$sql = "SELECT name FROM kensa WHERE karteNo = ? ORDER BY hizuke DESC LIMIT 1 ;";
$stmt = $pdo -> prepare($sql);
$stmt -> execute(array( $karteNo ));
$row = $stmt->fetch();
$ptName = $row['name'] ;
$this -> ptName = $ptName;
}catch (PDOException $e){
echo('Error:'.$e->getMessage());
die();
}
}
public function kekka( $karteNo ) // カルテ番号から検査結果
{
try{
$pdo = new PDO('sqlite:db/lapis.sql3','' ,'' ,array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$sql = "SELECT hizuke, koumokuNo, Kekka, KijyunMin, KijyunMax FROM kekka WHERE (hizuke, uketukeNo) IN (SELECT hizuke, uketukeNo FROM kensa WHERE karteNo = ?) ORDER BY hizuke DESC;";
$stmt = $pdo->prepare($sql);
$stmt->execute(array( $karteNo ));
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$kekkaArr[] = array($row['hizuke'], $row['koumokuNo'], $row['Kekka'], $row['KijyunMin'], $row['KijyunMax']) ;
}
$this -> kekkaArr = $kekkaArr ;
}catch (PDOException $e){
echo('Error:'.$e->getMessage());
die();
}
}
public function deleteNull() // 結果が null を削除
{
$kekkaArr = $this -> kekkaArr ;
$temp = $this -> temp ;
foreach( $kekkaArr as $eachline )
{
if( $eachline[2] != null ) {
$temp[] = $eachline ;
}
}
$this -> kekkaArr = $temp ;
}
public function hkArr() // 日付と項目番号を重複なしで配列化してソート
{
$kekkaArr = $this -> kekkaArr ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
foreach( $kekkaArr as $eachline )
{
if( !in_array( $eachline[0], $hizukeArr ) ){
$hizukeArr[] = $eachline[0] ;
}
if( !in_array( $eachline[1], $koumokuNoArr ) ){
$koumokuNoArr[] = $eachline[1] ;
}
}
rsort( $hizukeArr );
sort( $koumokuNoArr );
$this -> hizukeArr = $hizukeArr ;
$this -> koumokuNoArr = $koumokuNoArr ;
}
public function initTbl() // 最終的なテーブルを初期化しておく
{
$tableData = $this -> tableData ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
$gyo = count($koumokuNoArr) ;
$retu = count($hizukeArr) ;
for( $i=0; $i < $gyo; $i++) {
for( $j=0; $j < $retu; $j++) {
$tableData[$i][$j] = null ;
}
}
$this -> tableData = $tableData ;
}
public function initHantei() // 判定テーブルの初期化
{
$kekkaHantei = $this -> kekkaHantei ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
$gyo = count($koumokuNoArr) ;
$retu = count($hizukeArr) ;
for( $i=0; $i < $gyo; $i++) {
for( $j=0; $j < $retu; $j++) {
$kekkaHantei[$i][$j] = null ;
}
}
$this -> kekkaHantei = $kekkaHantei ;
}
public function createSheet() // 日付と項目番号で検索して検査結果を書き込んでいく
{
$kekkaArr = $this -> kekkaArr ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
$tableData = $this -> tableData ;
foreach( $kekkaArr as $eachline ){
$hizuke = $eachline[0] ;
$koumokuNo = $eachline[1] ;
$eachData = $eachline[2] ;
$xkey = array_search( $hizuke, $hizukeArr );
$ykey = array_search( $koumokuNo, $koumokuNoArr );
$tableData[$ykey][$xkey] = $eachData ;
}
$this -> tableData = $tableData ;
}
public function hantei()
{
$kekkaArr = $this -> kekkaArr ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
$kekkaHantei = $this -> kekkaHantei ;
foreach( $kekkaArr as $eachline )
{
$hizuke = $eachline[0] ;
$koumokuNo = $eachline[1] ;
$kekka = $eachline[2] ;
$min = $eachline[3] ;
$max = $eachline[4] ;
$xkey = array_search( $hizuke, $hizukeArr );
$ykey = array_search( $koumokuNo, $koumokuNoArr );
if( $kekka < $min ) {
$kekkaHantei[$ykey][$xkey] = "low" ;
}elseif( $kekka > $max ) {
$kekkaHantei[$ykey][$xkey] = "high" ;
}
}
$this -> kekkaHantei = $kekkaHantei ;
}
public function koumokuName() // koumokuMST から検査項目番号と検査項目名の対応表作成
{
$koumokuNameArr = $this -> koumokuNameArr ;
try{
$pdo = new PDO('sqlite:db/lapis.sql3','' ,'' ,array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
$sql = "SELECT koumokuNo, koumokuName FROM koumokuMST ;";
$stmt = $pdo->prepare($sql);
$stmt->execute();
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
$koumokuNameArr[] = array( $row['koumokuNo'], $row['koumokuName'] ) ;
}
$this -> koumokuNameArr = $koumokuNameArr ;
}catch (PDOException $e){
echo('Error:'.$e->getMessage());
die();
}
}
public function createTable() // 出力するテーブルを作成
{
$tableData = $this -> tableData ;
$hizukeArr = $this -> hizukeArr ;
$koumokuNoArr = $this -> koumokuNoArr ;
$koumokuNameArr = $this -> koumokuNameArr ;
$kekkaHantei = $this -> kekkaHantei ;
$ptName = $this -> ptName ;
$lineNum = 0 ;
echo "<p>$ptName<input type='button' value='印刷' class='print'></p>" ;
$tbl = "<table _fixedhead='rows:1; cols:1;'>\n";
//----------------- 一番上の行を追加 -- 日付の行
array_unshift( $hizukeArr, "項目" ); // 項目のカラムを追加
$header = "" ;
foreach( $hizukeArr as $key => $hizuke )
{
if( $key === 0 )
{
$eh = $hizuke ;
}else{
$eh = date( "Y-m-d", strtotime($hizuke)) ;
}
$header .= "<th>$eh</th>" ;
}
$tbl .= "<tr>{$header}</tr>\n" ;
//------------------ 各データ行を追加
foreach( $tableData as $rkey => $eachline )
{
$searchkey = array_search( $koumokuNoArr[$lineNum], array_column( $koumokuNameArr, 0));
$koumokuName = $koumokuNameArr[$searchkey][1] ;
$datas = "" ;
foreach( $eachline as $ckey => $val )
{
$hantei = $kekkaHantei[$rkey][$ckey] ;
if( $hantei === 'high') {
$datas .= "<td class='high'>$val</td>";
}elseif( $hantei === 'low' ) {
$datas .= "<td class='low'>$val</td>";
}else{
$datas .= "<td>$val</td>";
}
}
$tbl .= "<tr><th class='koumoku'>$koumokuName</th>$datas</tr>\n" ;
$lineNum++ ;
}
$tbl .= "</table>" ;
echo "<div class='container'>{$tbl}</div>" ;
}
}
//-----------------------------------
$karteNo = $_GET['karteNo'] ;
if( $karteNo == null )
{
echo "<p>カルテ番号が入力されていません。</p>" ;
exit() ;
}else {
$dataK = new dataKarte() ;
$dataK -> pName( $karteNo ) ;
$dataK -> kekka( $karteNo ) ;
$dataK -> deleteNull() ;
$dataK -> hkArr() ;
$dataK -> koumokuName();
$dataK -> initTbl() ;
$dataK -> createSheet() ;
$dataK -> initHantei() ;
$dataK -> hantei() ;
$dataK -> createTable() ;
}
?>
<script type="text/javascript">
var karteNo = JSON.parse('<?php echo $karteNo; ?>');
</script>
<script>
window.onload = function()
{
FixedMidashi.create();
};
</script>
</body>
</html>