0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

INSERT文のカラムと値を一覧化しました。

Last updated at Posted at 2022-10-21

経緯

INSERT文を修正する際に、使用している値がどのカラムの値なのか
一目でわからなかったため作成しました。

画面

image.png

画面半分にして使用するのを前提としているので全画面表示だと表示位置がずれます。

コード

コピペしてHTMLファイル作成すれば動きます。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Easy Insert</title>
    <script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>

    <style name="insertDataStyle">
      .useData, .unUseData {
        width: 50%;
        margin-top: 10px;
        /* 下記二つでblockを中央寄せ */
        margin-left: auto;
        margin-right: auto;
      }

      #dataLength {
        width: 50px;
        margin-left: 7rem;
      }

      .scrollInner {
        border: solid 1px;
        width: 100%;
        margin-top: 5px;
        /* スクロールバー追加 */
        overflow-y: scroll;
      }

      .useScroll {
        height: 342px;
      }

      .unUseScroll {
        height: 185px;
      }

      tbody {
        cursor: pointer;
      }

      td {
        height: 10px;
        border: solid 1px;
      }

      th{
        /* テーブルヘッダ固定 */
        background-color: white;
        position: sticky;
        top: 0;
        left: 0;
        z-index: 1;
      }

      .tableColName {
        width: 8rem;
      }

      .tableData {
        width: 14rem;
      }

      .tableButton {
        width: 2.7rem;
      }

      td input {
        border: none;
        height: 1.4rem;
        width: 94%;
      }

      .tableNo {
        text-align: center;
      }

      .btn {
        margin-left: 9px;
        width: 5rem;
      }

      #convertBtn {
        letter-spacing: 10px;
        text-align: center;
        padding-left: 10px;
      }

      #clearBtn {
        letter-spacing: 4px;
      }
  </style>
  <style name="inputQueryStyle">
    .inputQuery {
      width: 50%;
      margin-left: auto;
      margin-right: auto;
      margin-top: 30px;
    }
  </style>
  <style name="createQueryStyle">
    .createQuery {
      width: 50%;
      margin-left: auto;
      margin-right: auto;
      margin-top: 10px;
    }

    #createBtn {
      position: relative;
      left: 20rem;
    }
  </style>
  <style name="common">
    body {
      width: 930px;
    }

    textarea {
      margin-top: 5px;
      width: 100%;
      resize: vertical;
    }
  </style>
  </head>
  <body>
    <div class="inputQuery">
      <label for="inputQuery">クエリ入力:</label>
      <button class="btn" onclick="sample(1)">サンプル1</button>
      <button class="btn" onclick="sample(2)">サンプル2</button>
      <button class="btn" id="clearBtn" onclick="clearInputQuery()">クリア</button>
      <button class="btn" id="convertBtn" onclick="convert()">変換</button>
      <textarea id="inputQuery"></textarea><br>
    </div>

    <div class="inputData">
      <div class="useData">
        <label class="blockLabel">使用データ</label>
        <input type="text" placeholder="tableName" id="tableName">
        <input type="number" readonly value="0" id="dataLength">
        <label for="dataLength"></label>

        <div class="useScroll scrollInner">
          <table border="1">
            <thead>
              <tr>
                <th class="tableNo">No</th>
                <th class="tableColName">列名</th>
                <th class="tableData"></th>
                <th class="tableButton"></th>
              </tr>
            </thead>
            <tbody id="useTbody"></tbody>
          </table>
        </div>
      </div>

      <div class="unUseData">
        <label for="tableName">未使用データ</label>
        <button id="createBtn" onclick="create()">生成</button>
        <div class="unUseScroll scrollInner">
          <table border="1">
            <thead>
              <tr>
                <th class="tableNo">No</th>
                <th class="tableColName">列名</th>
                <th class="tableData"></th>
                <th class="tableButton"></th>
              </tr>
            </thead>
            <tbody id="unUseTbody"></tbody>
          </table>
        </div>
      </div>
    </div>

    <div class="createQuery">
      <textarea readonly id="createQuery"></textarea>
    </div>
    
    <script name="dispLoad">
      // SortableJS
      const useTbody = document.querySelector('#useTbody');
      Sortable.create(useTbody, {
        group: 'shared',
        draggable: '.item',
        onEnd: () => rowsChange(),
        onRemove: () => rowsChange(),
        onAdd: (evt) => {
          rowsChange();
          addBtnDisabledChange(evt.item);
        }
      });
      const unUseTbody = document.querySelector('#unUseTbody');
      Sortable.create(unUseTbody, {
        group: 'shared',
        draggable: '.item',
        onAdd: (evt) => addBtnDisabledChange(evt.item)
      });
    </script>        
    <script name="function">
      function convert() {
        const query = document.querySelector('#inputQuery').value;

        // insert文内の文字検索
        const searchWordDict = {
          into: 'into'
          , values: 'values'
          , beginbracket: '('
          , endbracket: ')'
        }
        
        // insert文のカラム名が省略されていないか確認
        const colExist = (query.match(new RegExp(/\(/, 'g' ) ) || [] ).length === 2 
          ? true : false ;

        // テーブル名を取得
        // insert into tb (col1) values (val1)
        const tableNameEndIdx = colExist
          ? query.indexOf(searchWordDict.beginbracket) 
          : query.toLowerCase().indexOf(searchWordDict.values);

        const tableName = query
          .substring(0 , tableNameEndIdx)
          .substr(query.toLowerCase()
            .indexOf(searchWordDict.into) + searchWordDict.into.length
          ).trim();

        document.querySelector('#tableName').value = tableName;

        // 列名
        const colNameList = (() => {
          if (colExist) {
            const colName = query
            .substring(0, query.indexOf(searchWordDict.endbracket))
            .substr(query.indexOf(searchWordDict.beginbracket) + 1)

            return colName.split(',');
          }
          return [];
        })();

        // 値
        const data = query
          .substr(query.lastIndexOf(searchWordDict.beginbracket) + 1)
          .replace(`${searchWordDict.endbracket};`, '');
        
        const dataList = query === '' ? [] : data.split(',');

        // 初期化
        document.querySelector('#useTbody').innerHTML = '';

        // テーブルにデータをセット
        createRows(colNameList, dataList, dataList.length, -1);
      }

      function createRows(inColNameList, inDataList, inRowsCount, inAddIdx) {
        const colNameList = inColNameList;
        const dataList = inDataList;
        const rowsCount = inRowsCount;
        const addIdx = inAddIdx;

        const table = document.querySelector('#useTbody');

        for(let i=0; i < rowsCount; i++) {
          const newRow = table.insertRow(addIdx);
          // SortableJSの対象を設定(tbodyのデータ)
          newRow.setAttribute('class','item');
          newRow.setAttribute('onDblclick','changeColor(this)');

          // No
          const newNo = document.createTextNode('');
          const newNoCell = newRow.insertCell();
          newNoCell.setAttribute('class','tableNo');
          newNoCell.appendChild(newNo);
          
          // ColName
          const newColName = document.createElement('input');
          newColName.setAttribute('type', 'text');
          newColName.setAttribute('placeholder', 'colName');
          newColName.setAttribute('class', 'inputTableColName');
          newColName.setAttribute('value', `${colNameList[0] ? colNameList[i].trim() : ''}`);
          const newColNameCell = newRow.insertCell();
          newColNameCell.setAttribute('class','tableColName');
          newColNameCell.appendChild(newColName);

          // Data
          const newData = document.createElement('input');
          newData.setAttribute('type', 'text');
          newData.setAttribute('placeholder', 'Data');
          newData.setAttribute('class', 'inputTableData');
          newData.setAttribute('value', `${dataList[0] ? dataList[i].trim() : ''}`);
          const newDataCell = newRow.insertCell();
          newDataCell.setAttribute('class','tableData');
          newDataCell.appendChild(newData);

          // Button
          const newBtn = document.createElement('button');
          newBtn.setAttribute('class', 'inputTableButton');
          newBtn.setAttribute('onClick', 'createRows([], [], 1, this.parentElement.parentElement.querySelector(\'td\').textContent)');
          newBtn.textContent = '追加';
          const newBtnCell = newRow.insertCell();
          newBtnCell.appendChild(newBtn);
        }
        rowsChange();
      }

      function create() {
        const tableName = document.querySelector('#tableName').value;
        const inputColNameList = document.querySelectorAll('#useTbody .inputTableColName');
        const inputDataList = document.querySelectorAll('#useTbody .inputTableData');

        const colExist = !!inputColNameList[0].value;
        const colName = (() => {
          let colName = '';

          if(colExist) {
            colName = ' (';
            inputColNameList.forEach(element => {
              colName += `${element.value}, `
            });
            colName = colName.slice(0, -2);
            return colName += ')';
          }
          return colName;
        })();

        const data = (() => {
          let data = '';
          inputDataList.forEach(element => {
            data += `${element.value}, `
          });
          return data.slice(0, -2);
        })();

        const query = `INSERT INTO ${tableName}${colName} VALUES (${data});`;
        document.querySelector('#createQuery').value = query;
      }

      function rowsChange() {
        const elm = document.querySelectorAll('#useTbody tr td.tableNo');
        for(let i=0; i < elm.length; i++) {
          elm[i].textContent = i + 1;
        }
        document.querySelector('#dataLength').value = elm.length;
      }
      
      function changeColor(elm) {
        const style = elm.style;
        style.backgroundColor = style.backgroundColor === '' ? 'skyblue' : '';
      }

      function addBtnDisabledChange(elm) {
        const addBtn = elm.querySelector('.inputTableButton');
        addBtn.disabled = addBtn.disabled ? false : true;
      }

      function sample(type) {
        const text = (() => {
          let textCol = '';
          let textData = 'VALUES (';
          for(let i=1; i<21; i++) {
            textCol += type === 1 ? `col${i}, ` : '';
            textData += `data${i}, `
          }
          textCol = textCol.slice(0, -2);
          return `INSERT INTO TABLE ${textCol === '' ? '' : `(${textCol}) `}${textData.slice(0, -2)});`;
        })();        
        document.querySelector('#inputQuery').value = text;
      }

      function clearInputQuery() {
        document.querySelector('#inputQuery').value = '';
      }
    </script>
  </body>
</html>

動作

初期表示

image.png

サンプルボタン押下

サンプル用のINSERT文が表示されます。
image.png

変換ボタン押下

入力されているINSERT文の内容からテーブルに値をセットします。
image.png

生成ボタン押下

テーブルの内容からINSERT文を生成します。
image.png

テーブルNoドラッグ

1 同じテーブル内でNoをドラッグした場合、列名と値が移動します。
image.png

2 テーブルをまたいで、ドラッグも可能です。
未使用データテーブルの追加ボタンは非活性です。
また、生成ボタン押下時のINSERT文の対象外です。
image.png

行をダブルクリック

ダブルクリックをした行に色が付きます。
image.png

追加ボタン押下

押した追加ボタンの1行下に行を作成します。
image.png

参考記事

行の並び替えに使用
https://sortablejs.github.io/Sortable/

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?