SQL整形ツール

ログファイルなどに出力されるSQLを整形する。
主な機能は以下。

・INSERT文、UPDATE文を整形する
・SQL文のカラム名を和名に変更
・キャメル式⇔スネーク式の変換
・大文字⇔小文字の変換


###### 例：INSET文の整形
![_C__workspaceLob2_4_7_0_00_JsProject_formatSQL.html (1).png](https://qiita-image-store.s3.amazonaws.com/0/289724/c5dd8f73-844a-4159-2303-b1f6693f5950.png)


###### 例：SQL文の「物理名 → 論理名」変換
※「物理名」「論理名」に値を設定しておく必要がある。

![_C__workspaceLob2_4_7_0_00_JsProject_formatSQL.html (2).png](https://qiita-image-store.s3.amazonaws.com/0/289724/a329df1e-5bec-62b0-a406-072087975909.png)




以下、コード。


### htmlファイル

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">

<script src="https://cdn.jsdelivr.net/jquery/3.1.0/jquery.min.js"></script>
<script src="js/formatSQL.js"></script>
<link rel="stylesheet" type="text/css" href="css/nomaliza.css">
<link rel="stylesheet" type="text/css" href="css/baseStyle.css">
<title>フォーマットSQL</title>
</head>
<body>

	<div id="header">
		<p>SQL変換ツール</p>
	</div>

	<div id="contents">
		<div id="content-00">
			<div id="b-area-01">
				<button type="button" onclick="exeFormat()">カラム名・値
					摘出(INSERT or UPDATE のみ対象)</button>
				<button onclick="changeLogicNameToSql()">SQL文 変換(物理名 → 論理名)</button>
			</div>

			<div id="b-area-02">
				<div class="b-area-02-inner">
					<span>変換先：</span>
					<!--  -->
					<select id="targetVal">
						<option value="formatColumn">SQLカラム名</option>
						<option value="formatValue">SQL値</option>
						<option value="physicalName">物理名</option>
					</select>
				</div>
				<div class="b-area-02-inner">
					<button onclick="changeTxtType()">キャメル式 ⇔ スネーク式 変換</button>
					<button onclick="changeUpperLower()">大文字 ⇔ 小文字 変換</button>
				</div>
				<span class="clear"></span>
			</div>

			<div class="b-area-03">
				<button onclick="clearTxtVal()">全てクリア</button>
			</div>

			<span class="clear"></span>
		</div>


		<div id="content-01">
			<div id="base">
				<div>SQL文</div>
				<textarea id="baseSQL" wrap="off"></textarea>
			</div>


			<div id="column">
				<div>SQLカラム名</div>
				<textarea id="formatColumn" wrap="off"></textarea>
			</div>


			<div id="value">
				<div>SQL値</div>
				<textarea id="formatValue" wrap="off"></textarea>
			</div>

			<div id="physicalNameArea">
				<div>物理名</div>
				<textarea id="physicalName" wrap="off"></textarea>
			</div>

			<div id="logicNameArea">
				<div>論理名</div>
				<textarea id="logicName" wrap="off"></textarea>
			</div>

			<span class="clear"></span> <span class="clear"></span>
		</div>

	</div>


</body>
</html> 

```



### JavaScript
#### formatSQL.js

```javascript

var insertTxtFlg;
var columnBracketsFlg;
var valFlg;
var valBracketsFlg;

var updateTxtFlg;
var setFlg;
var equalFlg;

/**
 * SQLをフォーマットする
 */
function exeFormat() {

	// 入力されたSQLの改行コードを\nに変換、スペース、シングルコーテーションを削除
	var baseSQL = $('#baseSQL').val() //
	.replace(/\(/g, " ( \n") // ( の後に改行コードを追加
	.replace(/\)/g, " ) \n") // ) の後に改行コードを追加
	// .replace(/\r\n|\r| |,/g, "\n") // 改行コード、スペースを \nに変換
	.replace(/\s|,/g, "\n") // 改行コード、スペースを \nに変換
	.replace(/'/g, ""); //

	initFlg();

	var columnArray = new Array();
	var valArray = new Array();

	// SQLをカラムと値に分ける
	var strList = baseSQL.split('\n');
	strList.some(function(thisTxt) {

		// スペースの削除
		thisTxt = thisTxt.trim();
		if (thisTxt == "") {
			return;
		}

		// INSERT文の整形
		if (divideInsert(thisTxt, columnArray, valArray)) {
			return;
		}

		// UPDATE文の整形
		if (divideUpdate(thisTxt, columnArray, valArray)) {
			return;
		}

	});

	var columnStr = columnArray.join('\r\n');
	if (columnStr.length == 0) {
		columnStr = "カラム名を摘出できません。"
	}
	$('#formatColumn').val(columnStr);

	var valStr = valArray.join('\r\n');
	if (valStr.length == 0) {
		valStr = "値を摘出できません。"
	}
	$('#formatValue').val(valStr);

}

/**
 * SQL文の物理名を論理名に変換する
 *
 * @returns
 */
function changeLogicNameToSql() {

	var physicalNameArray = createArrayTextAreaVal($("#physicalName").val());
	var logicNameArray = createArrayTextAreaVal($("#logicName").val());

	var baseSQL = $("#baseSQL").val();
	var changeSQL = baseSQL.replace(/[\n\|\r\n]/g, "\n ");

	physicalNameArray.some(function(thisTxt, idx) {

		var targetLogicName = logicNameArray[idx];
		if (thisTxt == "" || targetLogicName == "" || !targetLogicName) {
			return;
		}

		var regex = new RegExp(
				"(?<=[ |,|*|\(])" + thisTxt + "(?=[ |,|\n|\r\n|*|\)])", "gi");

		if (changeSQL.match(regex)) {
			changeSQL = changeSQL.replace(regex, logicNameArray[idx])
		}

	});

	changeSQL = changeSQL.replace(/\n /g, "\n");

	$("#baseSQL").val(changeSQL);
}

/**
 * 入力されたSQLの改行コードを正規表現により変換する
 *
 * @returns
 */
function createArrayTextAreaVal(targetVal) {

	var baseVal = targetVal.replace(/\(/g, " ( \n") // ( の後に改行コードを追加
	.replace(/\)/g, " ) \n") // ) の後に改行コードを追加
	// .replace(/\r\n|\r| |,/g, "\n") // 改行コード、スペースを \nに変換
	.replace(/\s|,/g, "\n") // 改行コード、スペースを \nに変換
	.replace(/'/g, "");

	return baseVal.split('\n'); //
}

/**
 * 入力されたSQLの改行コードを正規表現により変換する（元とSQLの形に戻す用）
 *
 * @param targetVal
 * @returns
 */
function createArrayTextAreaValForRevers(targetVal) {

	var baseVal = targetVal.replace(/\r\n|\n/g, " TMP_END_ROW_ELEMENT\n");

	return createArrayTextAreaVal(baseVal);

}

/**
 * フラグの初期化
 */
function initFlg() {
	insertTxtFlg = false;
	columnBracketsFlg = false;
	valFlg = false;
	valBracketsFlg = false;
	updateTxtFlg = false;
	setFlg = false;
	equalFlg = false;
}

/**
 * INSERT文の整形を行う
 *
 * @returns INSERT文の整形結果（ture：insert文の整形済み、false：insert文の整形をしていない）
 */
function divideInsert(thisTxt, columnArray, valArray) {

	if (thisTxt == "INSERT" || thisTxt == "insert") {
		insertTxtFlg = true;
		return true;
	}

	if (insertTxtFlg && thisTxt == "(") {
		columnBracketsFlg = true;
		return true;
	}

	// カラム名のみリストに格納
	if (insertTxtFlg && columnBracketsFlg && thisTxt != ")") {
		columnArray.push(thisTxt);
		return true;
	}

	if (insertTxtFlg && columnBracketsFlg && thisTxt == ")") {
		insertTxtFlg = false;
		columnBracketsFlg = false;
		return true;
	}

	if (thisTxt == "VALUES" || thisTxt == "values") {
		valFlg = true;
		return true;
	}

	if (valFlg && thisTxt == "(") {
		valBracketsFlg = true;
		return true;
	}

	// 値のみリストに格納
	if (valFlg && valBracketsFlg && thisTxt != ")") {
		valArray.push(thisTxt);
		return true;
	}

	if (valFlg && valBracketsFlg && thisTxt == ")") {
		valFlg = false;
		valBracketsFlg = false;
		return true;
	}

	return false;
}

/**
 *
 * @returns UPDATE文の整形結果（ture：insert文の整形済み、false：insert文の整形をしていない）
 */
function divideUpdate(thisTxt, columnArray, valArray) {

	// WHERE句の場合は初期化
	if (thisTxt == "WHERE" || thisTxt == "where") {
		initFlg();
		return true;
	}

	if (thisTxt == "UPDATE" || thisTxt == "update") {
		updateTxtFlg = true;
		return true;
	}

	if (updateTxtFlg && (thisTxt == "SET" || thisTxt == "set")) {
		setFlg = true;
		return true;
	}

	// カラム名のリストに格納
	if (updateTxtFlg && setFlg && !equalFlg && thisTxt != "=") {
		columnArray.push(thisTxt);
		return true;
	}

	// イコールフラグを設定
	if (updateTxtFlg && setFlg && thisTxt == "=") {
		equalFlg = true;
		return true;
	}

	// 値のリストに格納
	if (updateTxtFlg && setFlg && thisTxt && equalFlg) {
		valArray.push(thisTxt);
		equalFlg = false;
		return true;
	}

	return false;
}

/**
 * カラム名の 大文字 ⇔ 小文字 の変換を行う
 */
function changeUpperLower() {

	var targetId = $('#targetVal').val();
	if (!targetId) {
		return;
	}

	var columnStr = $('#' + targetId).val();

	if (columnStr.match(/[A-Z]/g)) {
		columnStr = columnStr.toLowerCase();
	} else {
		columnStr = columnStr.toUpperCase();
	}

	$('#' + targetId).val(columnStr);
}

/**
 * カラム名のスネークケース ⇔ キャメルケース の変換を行う
 */
function changeTxtType() {

	var targetId = $('#targetVal').val();
	if (!targetId) {
		return;
	}

	if ($('#' + targetId).val().match(/_/g)) {
		snakeToCamel(targetId);
	} else {
		camelToSnake(targetId);
	}

}

/*--- スネークケースをキャメルケースにする ---*/
// 返値 文字列(camelCase)
function snakeToCamel(targetId) {

	var camelStrArray = new Array();
	var columnStr = $('#' + targetId).val().split('\n');

	columnStr.some(function(thisTxt) {
		// _+小文字を大文字にする(例:_a を A)
		camelStrArray.push(thisTxt.replace(/_./g, function(s) {
			return s.charAt(1).toUpperCase();
		}));
	});

	$('#' + targetId).val(camelStrArray.join("\r\n"));

}
/*--- キャメルケースをスネークケースにする ---*/
// 返値 文字列(camel_case)
function camelToSnake(targetId) {

	var snakeStrArray = new Array();
	var columnStr = $('#' + targetId).val().split('\n');

	columnStr.some(function(thisTxt) {
		// 大文字を_+小文字にする(例:A を _a)

		var snakeStr = thisTxt.replace(/([A-Z])/g, function(s) {
			return '_' + s.charAt(0).toLowerCase();
		})
		snakeStrArray.push(snakeStr.replace(/^_/g, ""));
	});

	$('#' + targetId).val(snakeStrArray.join("\r\n"));
}

/**
 * 全ての値をクリアする
 *
 * @returns
 */
function clearTxtVal() {
	$('#baseSQL').val("");
	$('#formatColumn').val("");
	$('#formatValue').val("");
	$('#physicalName').val("");
	$('#logicName').val("");
}

```


## Css
#### baseStyle.css

```css
@charset "UTF-8";

body {
	margin: 10px;
	font-size: 13px;
}

button {
	font-size: 13px;
}

#header, #contents {
	padding: 10px;
}

#content-01>div {
	float: left;
	margin: 10px;
	height: 700px;
}

div#physicalNameArea {
	margin-left: 100px;
}

#content-01 textarea {
	width: 100%;
	height: 97%;
}

#content-01 p {
	height: 5%;
	margin: 0px;
}

#base {
	width: 450px;
}

#column {
	width: 200px;
}

#value {
	width: 200px;
}

#tblNameArea {
	width: 430px;
}

#tblName {
	width: 100%;
}

#tblNameArea div {
	margin: 0px;
}

.clear {
	clear: both;
	display: block;
}

#content-00>div {
	float: left;
	display: inline-block;
}

#b-area-01, #b-area-02, #b-area-03 {
	margin-right: 170px;
}

#b-area-01>button {
	display: block;
	margin-bottom: 10px;
}

.b-area-02-inner {
	float: left;
}

.b-area-02-inner button {
	display: block;
	margin-bottom: 10px;
	margin-left: 10px;
}

```

#### nomaliza.css
```css
/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */

/* Document
   ========================================================================== */

/**
 * 1. Correct the line height in all browsers.
 * 2. Prevent adjustments of font size after orientation changes in iOS.
 */

html {
  line-height: 1.15; /* 1 */
  -webkit-text-size-adjust: 100%; /* 2 */
}

/* Sections
   ========================================================================== */

/**
 * Remove the margin in all browsers.
 */

body {
  margin: 0;
}

/**
 * Correct the font size and margin on `h1` elements within `section` and
 * `article` contexts in Chrome, Firefox, and Safari.
 */

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

/* Grouping content
   ========================================================================== */

/**
 * 1. Add the correct box sizing in Firefox.
 * 2. Show the overflow in Edge and IE.
 */

hr {
  box-sizing: content-box; /* 1 */
  height: 0; /* 1 */
  overflow: visible; /* 2 */
}

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */

pre {
  font-family: monospace, monospace; /* 1 */
  font-size: 1em; /* 2 */
}

/* Text-level semantics
   ========================================================================== */

/**
 * Remove the gray background on active links in IE 10.
 */

a {
  background-color: transparent;
}

/**
 * 1. Remove the bottom border in Chrome 57-
 * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
 */

abbr[title] {
  border-bottom: none; /* 1 */
  text-decoration: underline; /* 2 */
  text-decoration: underline dotted; /* 2 */
}

/**
 * Add the correct font weight in Chrome, Edge, and Safari.
 */

b,
strong {
  font-weight: bolder;
}

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */

code,
kbd,
samp {
  font-family: monospace, monospace; /* 1 */
  font-size: 1em; /* 2 */
}

/**
 * Add the correct font size in all browsers.
 */

small {
  font-size: 80%;
}

/**
 * Prevent `sub` and `sup` elements from affecting the line height in
 * all browsers.
 */

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

/* Embedded content
   ========================================================================== */

/**
 * Remove the border on images inside links in IE 10.
 */

img {
  border-style: none;
}

/* Forms
   ========================================================================== */

/**
 * 1. Change the font styles in all browsers.
 * 2. Remove the margin in Firefox and Safari.
 */

button,
input,
optgroup,
select,
textarea {
  font-family: inherit; /* 1 */
  font-size: 100%; /* 1 */
  line-height: 1.15; /* 1 */
  margin: 0; /* 2 */
}

/**
 * Show the overflow in IE.
 * 1. Show the overflow in Edge.
 */

button,
input { /* 1 */
  overflow: visible;
}

/**
 * Remove the inheritance of text transform in Edge, Firefox, and IE.
 * 1. Remove the inheritance of text transform in Firefox.
 */

button,
select { /* 1 */
  text-transform: none;
}

/**
 * Correct the inability to style clickable types in iOS and Safari.
 */

button,
[type="button"],
[type="reset"],
[type="submit"] {
  -webkit-appearance: button;
}

/**
 * Remove the inner border and padding in Firefox.
 */

button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
  border-style: none;
  padding: 0;
}

/**
 * Restore the focus styles unset by the previous rule.
 */

button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
  outline: 1px dotted ButtonText;
}

/**
 * Correct the padding in Firefox.
 */

fieldset {
  padding: 0.35em 0.75em 0.625em;
}

/**
 * 1. Correct the text wrapping in Edge and IE.
 * 2. Correct the color inheritance from `fieldset` elements in IE.
 * 3. Remove the padding so developers are not caught out when they zero out
 *    `fieldset` elements in all browsers.
 */

legend {
  box-sizing: border-box; /* 1 */
  color: inherit; /* 2 */
  display: table; /* 1 */
  max-width: 100%; /* 1 */
  padding: 0; /* 3 */
  white-space: normal; /* 1 */
}

/**
 * Add the correct vertical alignment in Chrome, Firefox, and Opera.
 */

progress {
  vertical-align: baseline;
}

/**
 * Remove the default vertical scrollbar in IE 10+.
 */

textarea {
  overflow: auto;
}

/**
 * 1. Add the correct box sizing in IE 10.
 * 2. Remove the padding in IE 10.
 */

[type="checkbox"],
[type="radio"] {
  box-sizing: border-box; /* 1 */
  padding: 0; /* 2 */
}

/**
 * Correct the cursor style of increment and decrement buttons in Chrome.
 */

[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
  height: auto;
}

/**
 * 1. Correct the odd appearance in Chrome and Safari.
 * 2. Correct the outline style in Safari.
 */

[type="search"] {
  -webkit-appearance: textfield; /* 1 */
  outline-offset: -2px; /* 2 */
}

/**
 * Remove the inner padding in Chrome and Safari on macOS.
 */

[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}

/**
 * 1. Correct the inability to style clickable types in iOS and Safari.
 * 2. Change font properties to `inherit` in Safari.
 */

::-webkit-file-upload-button {
  -webkit-appearance: button; /* 1 */
  font: inherit; /* 2 */
}

/* Interactive
   ========================================================================== */

/*
 * Add the correct display in Edge, IE 10+, and Firefox.
 */

details {
  display: block;
}

/*
 * Add the correct display in all browsers.
 */

summary {
  display: list-item;
}

/* Misc
   ========================================================================== */

/**
 * Add the correct display in IE 10+.
 */

template {
  display: none;
}

/**
 * Add the correct display in IE 10.
 */

[hidden] {
  display: none;
}


```