SQLの整形
SQLの整形
既存のSQLを人に優しい様式に整形する。
例
CREATE TABLE 作業スキーマ.ワーク
SELECT カラム1 , カラム2 , ...
FROM スキーマ1.テーブル1 TbX
LEFT JOIN スキーマ.テーブル2 TbY ON TbY.主キー = TbX.主キー
WHERE カラム3 = 定数3 AND
カラム4 <> 定数4
GROUP BY 1, 2
;
・英大文字、小文字で区別がない予約後を英大文字にする
・重要な予約語ごとに4字ずつ字下げする
・SELECTのカラムは一定間隔にする
・WHEREの比較演算子の位置を揃える
・行末の空白は除く
・演算子の前後、カンマの直後は空白 OR 改行とする
・改行、文字コードを一定(LF, UTF8)とする
・TabStopは空白4字に置き換える
・・・などとしていると解読しやすい気がする
そこで、自前で以下の整形プログラムを作成した。
URL https://github.com/murakami668/golang.git
Go言語のEXCEL処理ではまったこと
GoLangを始めました。
通常はPHPの5~50倍早い処理になります。
文字列処理が🔟倍程度はやくなります。
整数演算は2倍程度です。
エクセル処理は、5~6倍です。
ワーキングメモリの使い方がPHPより賢いので、EXCEL処理
が早いのですが、MSエクセル以外で作成したファイルの一部は、
PHPで読み込めるがGOで読み込めないものがあります。
MSエクセルで読んで書き直すと読み込めるようになるので、
単純なバグではない気がします。
用いたパッケージはgithub.com/tealeg/xlsxです。
Cellの位置がずれて読み込まれるのが原因のようですが、
Go本体のzipパッケージで読み込んだ時点ですでにずれているので、
github.com/tealeg/xlsxが原因ではなさそうです。
PHP 清書?整書
PHPプログラムにはいろんな清書・整書様式がある。
清書・整書の主観的な目的は見やすさであろうと思う。
清書を自動化してくれるツールもたくさんあるのだが、ツールで清書化する
とバグ(タイプミス)を発見する機会を自ら逃す場合もある。
と言うのは、1文字ずつ見なくてもバグのある行が周囲の行とのズレによって
一目で発見できることがあるからでる。
その前提は、行ごと気分次第にバラバラな書き方をしていないことが肝心で
ある。
しかし、ルールを守ろうとしても見落としてしまうのが人間であるし、その
ルールがプログラムを他人と共有化するためとかだったりすると、「ヤラサレ
感」によって注意が減退してしまうかもしれない。
よってルールはあくまでも自分自身が後で見るためのものと考えることにする
と、世に出回っていルールには自分にしっくりこないものを含んでいることが
気になってくる。
そこで、自分用のルールに従っているか否かをチェックするプログラムを作っ
てしまうことにした。
<PRE>
----------------------------------------------------------------------------------
<?php
error_reporting(E_ALL ^ E_NOTICE);
//****************************************************************************
//* 次に記述するコーディング規約に準拠していないプログラム名とその行番号と
//* 行の内容そのものをリストアップする。
//*
//* ・改行はUNIX形式の「0x0A」1文字のみとする。
//* ・タブは使わない。
//* ・改行に先行する空白は除去する。
//* ・文字列は二重引用符のみで囲む。
//* ・「if」,「for」等の制御文の内部は4桁ずつインデントする。
//* ・「if」,「for」等の制御文や「+」,「-」等の演算子は空白で分離する。
//* ・「and」,「or」,「as」等は分離してる場合のみ演算子なので検査しない。
//* ・「{」,「}」はそれのみで1行を占める。
//* ・直前行の末尾が演算子で終わっている場合は、最先非空白,「”」、「’」、
//* 「$」、「[」の位置のいずれに一致させる。
//*
//* 制限事項
//* ・組み込みHTML区域は検査から除外する。
//* ・制御文の条件区が多行構造の場合は、行末が「)」で条件区完了とみなす。
//* ・カンマ「,」は後続空白のみ検査し、先行空白は検査しない。
//* ・演算子「++」,「--」,「=>」,「->」,「&$」,「::」は空白分離を検査しない。
//*
//* 著作権表示:
//* コーディング者 : 村上和夫
// ***************************************************************************
$Cnt = 0;
if ($argc < 2)
{
fprintf(STDOUT, mb_convert_encoding(”USAGE [最大表示行数 [ファイル除外先頭名 [ファイル限定先頭名]]]¥n” .
”4の倍数になるよう行頭空白も削除をあえて実行したいなら、¥n” .
”本メッセー出力部分をコメント化してください。¥n”, ”SJIS-win”));
exit;
ufn_cut1st_spc();
exit;
}
$Is_Dyadic_Oper = [ ”,”=>1, ”.”=>1, ”&”=>1, ”|”=>1, ”+”=>1, ”-”=>1, ”*”=>1, ”/”=>1, ”%”=>1, ”^”=>1 ];
$Is_Operator = [ ”,”=>1, ”.”=>1, ”&”=>1, ”|”=>1, ”+”=>1, ”-”=>1, ”*”=>1, ”/”=>1, ”=”=>1, ”>”=>1,
”<”=>1, ”!”=>1, ”%”=>1, ”^”=>1 ];
$Is_Prev_Oper = [ ”.”=>1, ”&”=>1, ”|”=>1, ”+”=>1, ”-”=>1, ”*”=>1, ”/”=>1, ”=”=>1, ”>”=>1, ”<”=>1,
”!”=>1, ”%”=>1, ”^”=>1 ];
$Is_Post_Oper = [ ”&”=>1, ”|”=>1, ”+”=>1, ”-”=>1, ”/”=>1, ”=”=>1, ”>”=>1 ];
$Is_Border_Char = [ ”¥””=>1, ”$”=>1, ”’”=>1, ”!”=>1 ];
$Is_Top_Of_Word = [ ”0”=>1, ”1”=>1, ”2”=>1, ”3”=>1, ”4”=>1, ”5”=>1, ”6”=>1, ”7”=>1, ”8”=>1, ”9”=>1,
”a”=>1, ”b”=>1, ”c”=>1, ”d”=>1, ”e”=>1, ”f”=>1, ”g”=>1, ”h”=>1, ”i”=>1, ”j”=>1,
”k”=>1, ”l”=>1, ”m”=>1, ”n”=>1, ”o”=>1, ”p”=>1, ”q”=>1, ”r”=>1, ”s”=>1, ”t”=>1,
”u”=>1, ”v”=>1, ”w”=>1, ”x”=>1, ”y”=>1, ”z”=>1, ”A”=>1, ”B”=>1, ”C”=>1, ”D”=>1,
”E”=>1, ”F”=>1, ”G”=>1, ”H”=>1, ”I”=>1, ”J”=>1, ”K”=>1, ”L”=>1, ”M”=>1, ”N”=>1,
”O”=>1, ”P”=>1, ”Q”=>1, ”R”=>1, ”S”=>1, ”T”=>1, ”U”=>1, ”V”=>1, ”W”=>1, ”X”=>1,
”Y”=>1, ”Z”=>1, ”$”=>1, ”(”=>1, ”{”=>1, ”_”=>1, ”¥”” , ”[”=>1, ”=”=>1, ];
$Is_Doble_Skip = [ ”<?”=>1, ”?>”=>1, ”=>”=>1, ”++”=>1, ”--”=>1, ”, ”=>1, ”*/”=>1, ”/*”=>1, ”->”=>1,
”::”=>1, ”&$”=>1 ];
$Is_Multi_Oper = [ ”<=”=>1, ”>=”=>1, ”!=”=>1, ”==”=>1, ”+=”=>1, ”-=”=>1, ”*=”=>1, ”/=”=>1, ”%=”=>1,
”.=”=>1, ”&=”=>1, ”|=”=>1, ”&&”=>1, ”||”=>1, ”<>”=>1, ”**”=>1, ”>>”=>1, ”<<”=>1,
”^=”=>1 ];
$Is_Triple_Oper = [ ”===”=>1, ”!==”=>1, ”>>=”=>1, ”<<=”=>1, ”&&=”=>1, ”||=”=>1 ];
$DspLim = 1;
if (ctype_digit($argv[1]))
$DspLim = $argv[1];
//fprintf(STDOUT, ”Limit Lines = %s ¥n”, $DspLim);
$HiDir = ””;
$Len = 0;
if ($argc > 3)
$HiDir = $argv[3];
if ($argc > 2)
$Len = strlen($argv[2]);
## print(”[DEBUG]HiDir=(” . $HiDir . ”)¥n”);
## print(”[DEBUG]Len(” . $Len . ”)¥n”);
foreach (glob($HiDir . ”*.php”) as $Php_File)
{
if ($Php_File === FALSE)
die(”PHPファイルを読込めませんでした。”);
if (($Len > 0) &&
(substr($Php_File, 0, $Len) == $argv[2]))
continue;
## print(”[DEBUG]File(” . $Php_File . ”)¥n”);
$CntFlg = $DspCnt = $LineCnt = $CtlFnd = $FndPos = $CtlPos = $LstPos = 0;
$Lst_Braces = $Lst_Pushin = $Html_Area = $Slsh_Astr = $QuoCont = $Closing = 0;
$Hnd_Inp = fopen($Php_File, ”r”);
$Lst_Buff = ””;
while ($Php_Buff = fgets($Hnd_Inp))
{
$LineCnt++;
if (substr($Php_Buff, 0, 5) == ”<?php”)
$Html_Area = 0;
else
if (substr($Php_Buff, 0, 2) == ”?>”)
$Html_Area = 1;
if (($Html_Area == 0 ) &&
($DspCnt < $DspLim ) &&
($Php_Buff[0] != ”¥n”) )
{
$Relation = $Extended;
$Extended = $Mode_4 = 0;
$LineEnd = strpos($Php_Buff, ”¥n”);
$LiEndChr = $Php_Buff[ ($LineEnd - 1) ];
if ($Is_Dyadic_Oper[$LiEndChr] == 1)
$Extended = 1;
// 現行よりまえの行見つかった制御文の行頭位置、条件区よりあとの行の行頭位置より4少ない。
$CtlPos = $FndPos;
$MltByt = $Braces = $Pushin = 0;
for ($nn = 0; $nn < $LineEnd; $nn++)
{
if ($Php_Buff[$nn] > ”~”)
$MltByt++;
if ($Php_Buff[$nn] != ” ”)
break;
}
$CurPos = $nn - floor($MltByt / 3);
$Mode_4 = $CurPos % 4;
$Border = $Php_Buff[$nn];
if (($Border == ”{”) && ($nn == $LineEnd - 1))
$Braces = 1;
else
if (($Border == ”}”) && ($nn == $LineEnd - 1))
$Braces = 2;
// ・「if」,「for」等の制御文の内部は4桁ずつインデントする。
if ((substr($Php_Buff, $nn, 3) == ”if ”) ||
(substr($Php_Buff, $nn, 3) == ”do ”) ||
(substr($Php_Buff, $nn, 4) == ”for ”) ||
(substr($Php_Buff, $nn, 5) == ”else ”) ||
(substr($Php_Buff, $nn, 6) == ”while ”) ||
(substr($Php_Buff, $nn, 7) == ”switch ”) ||
(substr($Php_Buff, $nn, 8) == ”foreach ”) ||
(substr($Php_Buff, $nn, 7) == ”elseif ”) )
{
$CtlFnd = 1;
$FndPos = $CurPos;
if (($LiEndChr != ”;”) &&
($Is_Dyadic_Oper[$LiEndChr] != 1))
$Pushin = 1;
}
if (($CtlFnd == 1) && ($LiEndChr == ”)”))
$Pushin = 1;
if (($LiEndChr == ”;”) || ($Pushin == 1))
$CtlFnd = 0;
// 前行が”{”なら CurPos - LstPos = 4 , 現行が”}” なら LstPos - CurPos = 4
if ((strpos($Php_Buff, ”//”) === FALSE) &&
($Lst_Braces == 1) && ($CurPos - $LstPos != 4) ||
(strpos($Lst_Buff, ”//”) === FALSE) &&
($Braces == 2) && ($LstPos - $CurPos < 4) )
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):10(Braces befr 4/aftr 4) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
if ($Lst_Braces == 1)
fprintf(STDOUT, ”#%4d]bra:%d/%d/ %s”, $LineCnt, $LstPos, $CurPos, $Php_Buff);
else
fprintf(STDOUT, ”#%4d]Bra:%d/%d/ %s”, $LineCnt, $LstPos, $CurPos, $Lst_Buff);
}
// 前行が”if ”かつ 行頭が ”(”,”{”でないなら CurPos - CtlPos = 4
if ((strpos($Php_Buff, ”//”) === FALSE) &&
($Lst_Pushin == 1) && ($CurPos - $CtlPos != 4) &&
($Border != ”(”) && ($Border != ”{”))
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):11(Hierarchy Indent) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
fprintf(STDOUT, ”#%4d]Hie:%d/%d/ %s”, $LineCnt, $CtlPos, $CurPos, $Php_Buff);
}
// ・「if」,「for」等の制御文や「+」,「-」等の演算子は空白で分離する。
if ((substr($Php_Buff, $nn, 3) == ”if(”) ||
(substr($Php_Buff, $nn, 3) == ”do(”) ||
(substr($Php_Buff, $nn, 4) == ”for(”) ||
(substr($Php_Buff, $nn, 5) == ”else(”) ||
(substr($Php_Buff, $nn, 6) == ”while(”) ||
(substr($Php_Buff, $nn, 7) == ”switch(”) ||
(substr($Php_Buff, $nn, 8) == ”foreach(”) ||
(substr($Php_Buff, $nn, 7) == ”elseif(”) )
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):12(Not Function Spc) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
$Pattn = substr($Php_Buff, strpos($Php_Buff, ”(”) - 2, 3);
fprintf(STDOUT, ”#%4d]Fnc:(%s) %s”, $LineCnt, $Pattn, $Php_Buff);
}
if (($nn < $LineEnd) &&
($Mode_4 > 0 ) &&
($Relation == 0 ) )
{
// ・4桁ずつインデントする。
if ((strpos($Lst_Buff, ”=>¥n”) === FALSE) &&
(strpos($Php_Buff, ”=>¥n”) === FALSE) )
{
if ($Is_Top_Of_Word[$Border] == 1)
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):%d(Indent Mode-4 !=0 ) %s¥n”, $Cnt, $Mode_4, $Php_File);
}
$DspCnt++;
fprintf(STDOUT, ”#%4d]Ind:(%d) %s”, $LineCnt, $Mode_4, $Php_Buff);
}
}
}
else
if (($Mode_4 > 0) &&
(($Lst_Buff[$nn] == ” ”) ||
($Lst_Buff[ ($nn - 1) ] != ” ”) ) )
{
if (($Relation == 1 ) &&
($Is_Border_Char[$Border] == 1) )
{
$Offset = strpos($Lst_Buff , ” = ”);
if ($Offset === FALSE)
{
$Offset = strpos($Lst_Buff , ” .= ”);
if ($Offset === FALSE)
{
$Offset = strpos($Lst_Buff , ” += ”);
if ($Offset === FALSE)
$Offset = 0;
}
}
$Lst_LineEnd = strpos($Lst_Buff, ”¥n”);
$MltByt = 0;
for ($kk = 0; $kk < $Lst_LineEnd; $kk++)
{
if ($Lst_Buff[$kk] > ”~”)
$MltByt++;
$LstPos = $kk - floor($MltByt / 3);
if ($LstPos >= $CurPos)
break;
}
$LstBorder = $Lst_Buff[$kk];
if ($Offset > 64)
$Offset = 64;
$LstBdrPos1 = strpos($Lst_Buff, ”¥””, $Offset);
$LstBdrPos2 = strpos($Lst_Buff, ”$” , $Offset);
$LstBdrPos3 = strpos($Lst_Buff, ”’” , $Offset);
$LstBdrPos4 = strpos($Lst_Buff, ”[” , $Offset);
// ・直前行の末尾が演算子で終わっている場合は、継続行は桁あわせをする
if ((strpos($Lst_Buff, ”//”) === FALSE) &&
(strpos($Php_Buff, ”//”) === FALSE) &&
(strpos($Lst_Buff, ”=>¥n”) === FALSE) &&
(strpos($Php_Buff, ”=>¥n”) === FALSE) &&
(strpos($Php_Buff, ”=> [”) === FALSE) &&
($LstBorder != $Border ) &&
(($LstBdrPos1 !== FALSE) ||
($LstBdrPos2 !== FALSE) ||
($LstBdrPos3 !== FALSE) ||
($LstBdrPos4 !== FALSE) ) &&
($LstBdrPos1 != $nn ) &&
($LstBdrPos2 != $nn ) &&
($LstBdrPos3 != $nn ) &&
($LstBdrPos4 != $nn ) )
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):5(Next Line SyncPos) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
fprintf(STDOUT, ”#%4d]Nxt: %s”, $LineCnt, $Php_Buff);
}
}
}
// ・改行に先行する空白は除去する。
if (strpos($Php_Buff, ” ¥n”))
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):6(Space Before LF) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
fprintf(STDOUT, ”#%4d]Spc: %s”, $LineCnt, $Php_Buff);
}
// ・タブは使わない。
if (strpos($Php_Buff, ”¥t”))
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):7(TabSet Is Used) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
$Pattn = substr($Php_Buff, $nn - 1, 3);
fprintf(STDOUT, ”#%4d]Tab:(%s) %s”, $LineCnt, $Pattn, $Php_Buff);
}
// ・改行はUNIX形式の0x0A1文字のみとす。
if (strpos($Php_Buff, ”¥r”))
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):8(CR + LF Invalid ) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
fprintf(STDOUT, ”#%4d]Rtn: %s”, $LineCnt, $Php_Buff);
}
if ($QuoCont == 0)
$Quoat = $Escape = 0;
$CurChar = $PreChar = $Bf2Char = $Af2Char = ””;
for ($nn = 0; $nn < $LineEnd; $nn++)
{
$Bf2Char = $PreChar;
$PreChar = $CurChar;
$CurChar = $Php_Buff[$nn];
$NxtChar = $Php_Buff[($nn + 1)];
if ($PreChar == ”¥¥”)
$Escape = 1 - $Escape;
else
$Escape = 0;
if (($CurChar == ”’”) || ($CurChar == ”¥””))
{
if (($CurChar == ”¥””) && ($Escape == 0))
$Quoat = 1 - $Quoat;
// ・文字列は二重引用符のみで囲む。
if (($CurChar == ”’”) && ($Quoat == 0))
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):9(Quoat Must Double) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
$Pattn = substr($Php_Buff, $nn - 1, 3);
fprintf(STDOUT, ”#%4d]Quo:(%s) %s”, $LineCnt, $Pattn, $Php_Buff);
break;
}
}
## print(”[DEBUG]LINE=” . $LineCnt . ”,QUOAT=” . $Quoat . ”,nn=” . $nn . ”,LineEnd=” . ($LineEnd - 1) .
## ”,PCN=” . $PreChar . $CurChar . $NxtChar . ”,Slsh_Astr=” . $Slsh_Astr . ”¥n”);
if (($Quoat == 0) && ($nn < $LineEnd - 1))
{
if ($CurChar == ”#”)
break;
else
if (($CurChar == ”/”) && ($NxtChar == ”/”))
break;
else
if (($CurChar == ”/”) && ($NxtChar == ”*”))
$Slsh_Astr = 1;
else
if (($CurChar == ”*”) && ($NxtChar == ”/”))
$Slsh_Astr = 0;
if (($Slsh_Astr == 0) && (($CurChar == ”{”) || ($CurChar == ”}”)))
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):13(Mixed Other Char) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
fprintf(STDOUT, ”#%4d]Mix: %s”, $LineCnt, $Php_Buff);
break;
}
## print(”[DEBUG]Slsh_Astr=” . $Slsh_Astr . ”,nn=” . $nn . ”,PCN=” . $PreChar . $CurChar . $NxtChar .
## ”,Is_Oper=” . $Is_Operator[$CurChar] . ”¥n”);
if (($Slsh_Astr == 0) && ($Is_Operator[$CurChar] == 1))
{
## print(”[DEBUG]nn=” . $nn . ”,LineEnd=” . ($LineEnd - 1) . ”,PCN=” . $PreChar . $CurChar . $NxtChar . ”¥n”);
if ($nn < $LineEnd - 2)
$Af2Char = $Php_Buff[($nn + 2)];
$Pre_Cur = $PreChar . $CurChar;
$Cur_Nxt = $CurChar . $NxtChar;
$Pre_Nxt = $PreChar . $CurChar . $NxtChar;
## fprintf(STDOUT, ”(%03d:%s:%s:[%s]:%s:%s) %s¥n”, $LineCnt, $Bf2Char, $PreChar, $CurChar, $NxtChar, $Af2Char, $Php_Buff);
// ・「+」,「-」等の演算子は空白で分離する。
## fprintf(STDOUT , ”[DEBUG]%3d PCN=(%s:%s:%s),%s”, $LineCnt, $PreChar, $CurChar, $NxtChar, $Php_Buff);
if (($Is_Triple_Oper[$Pre_Nxt] == 1) &&
(($Bf2Char != ” ”) ||
($Af2Char != ” ”) && ($Af2Char != ”¥n”)))
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):14(Operator Needs Spc) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
fprintf(STDOUT, ”#%4d]Op3:(%s%s%s) %s”, $LineCnt, $Bf2Char, $Pre_Nxt, $Af2Char, $Php_Buff);
break;
}
else
if ((substr($Php_Buff, 0, 5) == ”<?php”) ||
($Is_Doble_Skip[$Pre_Cur] == 1) ||
($Is_Doble_Skip[$Cur_Nxt] == 1) )
continue;
else
if (($Is_Multi_Oper[$Pre_Cur] == 1) &&
(($Bf2Char != ” ”) && ($Bf2Char != ”=”) && ($Bf2Char != ”!”) ||
($NxtChar != ” ”) && ($NxtChar != ”=”) && ($NxtChar != ”¥n”)))
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):14(Operator Needs Spc) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
fprintf(STDOUT, ”#%4d]Op2:(%s%s%s) %s”, $LineCnt, $Bf2Char, $Pre_Cur, $NxtChar, $Php_Buff);
break;
}
else
{
if ((($Is_Post_Oper[$NxtChar] != 1 ) &&
($NxtChar != ” ”) && ($NxtChar != ”¥n”) ||
($Is_Prev_Oper[$PreChar] != 1) &&
($PreChar != ” ” ) ) &&
(($CurChar != ”.”) || ! ctype_digit($NxtChar)) &&
(($CurChar != ”-”) || ! ctype_digit($NxtChar)) )
{
if ($DspCnt < 1)
{
$Cnt++;
fprintf(STDOUT, ”(%03d):14(Operator Needs Spc) %s¥n”, $Cnt, $Php_File);
}
$DspCnt++;
fprintf(STDOUT, ”#%4d]Op1:(%s%s%s) %s”, $LineCnt, $PreChar, $CurChar, $NxtChar, $Php_Buff);
break;
}
}
}
}
}
$Lst_Buff = $Php_Buff;
$LstPos = $CurPos;
$Lst_Braces = $Braces;
$Lst_Pushin = $Pushin;
if ($Quoat == 1)
$QuoCont = 1;
}
if (substr($Php_Buff, 0, 2) == ”?>”)
$Closing = $LineCnt;
}
fclose($Hnd_Inp);
if (($Closing != 0 ) &&
($Closing != $LineCnt ) &&
(substr($Php_File, 0, 3) != ”yk_”) &&
($LineCnt - $Closing < 4 ) )
{
$Cnt++;
fprintf(STDOUT, ”(%03d):20(Found Line After Closing) %s¥n”, $Cnt, $Php_File);
}
}
if ($Cnt == 0)
fprintf(STDOUT, ”No errors!¥n”);
exit;
?>
MySQLでクロス集計
SQLでクロス集計する際、該当がない項目も水平軸にしないと
漏れがでてしまうと考えたことはないでしょうか?
該当がある項目を2つ、縦に並べるのは標準で備わっているので
何の造作もないことでしょう。
例えば、
SELECT 縦カラム,横カラム名,COUNT(*) 件数
FROM スキーマ名.テーブル名
GROUP BY 縦カラム,横カラム名;
で完成です。
しかし、横カラムのデータを水平方向に並べた、所謂クロス集計
をしたいと思った途端、横カラムの異なるデータの個数が動的(
言い換えれば不定)なので、SQLを書くことができない。
ありうる全ての種類が受容限度以下なら、該当データが無いこと
を承知でSQLを書くこともできるでしょう。
実は、何個のカラムを用意すればいいのかは、SQLで直ぐわかって
しまうことです。
例えば, SELECT DISTINCT 横カラム名 FROM ....;
で済んでしまいます。
そこで、この結果を人間が見てSQLを書き下す代わりに、
SQL自分自身でSQLで作成する事はできないのかと言うことを
見ましょう。
そうすると、
SELECT 縦カラム,
式1 AS 横カラム1,
式2 AS 横カラム2,
...
式n AS 横カラムn
FROM ... GROUP BY 縦カラム;
生成できそうな気がしませんか?
SQLで生成しななくてもいい部分は、固定文字列にして
おけば完成のハズですね。
ではここで具体例を示します。
DROP TEMPORARY TABLE IF EXISTS temp.wrk ;
CREATE TEMPORARY TABLE temp.wrk
SELECT DISTINCT TbL.横カラム名
FROM スキーマ名.テーブル名 TbL
LEFT JOIN ~~~~~~
WHERE ~~~~~~ AND
~~~~~~ AND
. . . . . . . . .
~~~~~~ ;
DROP TEMPORARY TABLE IF EXISTS temp.tmp ;
CREATE TEMPORARY TABLE temp.tmp (cmd VARCHAR(128)) ;
INSERT INTO temp.tmp VALUES
("SELECT 式 AS 縦カラム) ;
INSERT INTO temp.tmp
(SELECT CONCAT(" SUM(", 縦カラム, ") AS ", 縦カラム, ", ") FROM temp.wrk);
INSERT INTO temp.tmp VALUES
(" SUM(合計) 合計 "),
(" FROM ("),
(" SELECT TbL.横カラム名,TbL.縦カラム名,") ;
INSERT INTO temp.tmp
(SELECT CONCAT(" SUM(IF(AcT.横カラム名='", 横カラム, "' , 1 ,0)) AS ", 横カラム, ",") FROM temp.wrk);
INSERT INTO temp.tmp VALUES
(" SUM(1) 合計"),
(" FROM スキーマ名.テーブル名 Tbl"),
(" LEFT JOIN ~~~~~~"),
(" WHERE ~~~~~~ AND"),
(" ~~~~~~ AND"),
. . . . . .. . . . . .
(" ~~~~~~"),
(" GROUP BY 1,2,"),
(" ) tmp"),
(" GROUP BY 1 WITH ROLLUP;"),;
SELECT * FROM temp.tmp
;