Node.jsからSQLiteを操作する方法

sqlite3を使うとNode.jsからSQLiteを操作できます。

バージョン

  • sqlite3 - 5.0.10

インストール

npm install sqlite3

使用方法

const sqlite3 = require('sqlite3').verbose();

// データベースに接続する.
let db = new sqlite3.Database(<データベースファイルのパス>);

db.all('<SQL文>', [パラメータ], (err, rows) => {
    if (err) {
        // エラー発生時.
        return;
    }
    // 取得データ rows に対する処理.
});

// データベースの切断.
db.close();

パラメータ渡しの例

パラメータ数と配列の要素数を同じにします。パラメータ無しの場合は[]を指定、または省略できます。

db.all('SELECT * FROM LOCAL_LOGS ORDER BY registered_at DESC LIMIT ?', [10], (err, rows) => {});

SELECT処理

SELECTには次の3つのメソッドが利用できます。

  • db.get() - 抽出結果の先頭1行のみを返します
    db.get('SELECT timestamp FROM LOCAL_LOGS WHERE timestamp > ? ORDER BY timestamp ASC LIMIT 1', ['2023-11-30 21:00'], (err, row) => {
        console.log(row);
    });

    rowには行データが格納されます。該当データなしの場合はundefinedです。

  • db.all() - 全ての抽出結果を返します
    db.all('SELECT timestamp FROM LOCAL_LOGS WHERE timestamp > ?', ['2023-11-30 21:00'],(err, rows) => {
        console.log(rows);
    });

    rowsには行データが配列形式で格納されます。該当データなしの場合は空配列([])になります。

  • db.each() - 抽出結果を順次コールバックで通知します
    db.each('SELECT timestamp FROM LOCAL_LOGS WHERE timestamp > ?', ['2023-11-30 21:00'], (err, row) => {
        // 抽出数分実行される.
        console.log(row);
    });

    コールバックが該当データ分実行されます。該当データなしの場合はコールバックが実行されません。

INSERT処理など

db.run()で非同期にSQL文を実行できます。

db.run('INSERT INTO LOCAL_LOGS (type, status) VALUES (?,?)', [1, 200]);

発行したSQL文を順番に実行したい場合はdb.serialize()メソッドを使います。

db.serialize(() => {
    db.run('CREATE TABLE SAMPLE(type, status)');
    db.run('INSERT INTO SAMPLE (type, status) VALUES (?,?)', [1, 200]);
    db.all('SELECT * FROM SAMPLE', (err, rows) => {
        console.log(rows);
    });
});

prepare()メソッド

複数データの登録を行う場合は、db.prepare()メソッドが利用できます。

db.serialize(() => {
    let statement = db.prepare('INSERT INTO SAMPLE (type, status) VALUES (?,?)');
    statement.run([1, 100]);
    statement.run([1, 200]);
    statement.run([2, 200]);
    statement.run([2, 400]);
    statement.finalize();
});

db.all('SELECT * FROM SAMPLE', (err, rows) => {
    console.log(rows);
});

nexeでexe化したときに次のエラーが出る場合の対処方法

nexeを使ってNode.jsプロジェクトをexe化して実行すると、次のようなエラーが発生しました。その時の対処方法。

Node v14

Error: The specified module could not be found.
\\?\C:\<プロジェクト>\node_modules\sqlite3\lib\binding\napi-v6-win32-unknown-x64\node_sqlite3.node

Node v12

Error: Cannot find module 'C:\<プロジェクト>\node_modules\sqlite3\lib\binding\napi-v3-win32-unknown-x64\node_sqlite3.node'

対処方法

  1. \node_modules\sqlite3\lib\binding\napi-v6-win32-unknown-x64ディレクトリをカレントディレクトリにコピーする
  2. \node_modules\sqlite3\package.jsonの次の箇所を書き換える
    • 変更前
      "binary": {
      "module_path": "./lib/binding/napi-v{napi_build_version}-{platform}-{libc}-{arch}",
      },
    • 変更後
      "binary": {
      "module_path": "../../napi-v{napi_build_version}-{platform}-{libc}-{arch}",
      },

実行時の構成

\napi-v6-win32-unknown-x64
  node_sqlite3.node
xxxxx.exe

ディレクトリ内のnode_sqlite3.nodeのみをカレントディレクトリにコピーしてパスを指定してもうまく動かないのでディレクトリごとコピーします。

Promise で返す方法

結果をpromiseで返却するサンプルです。selectHistoriesAsync()メソッド呼び出し側はawaitで結果を待つことができます。

selectHistoriesAsync() {
    return new Promise((resolve, reject) => {
        let db = new sqlite3.Database(<データベースファイルのパス>);
        db.all('SELECT * FROM HISTORIES', [], (err, rows) => {
            if (err) {
                reject('error reason');
                return;
            }
            resolve(rows);
        });
        db.close();
    });
}

Error: SQLITE_MISUSE: Database handle is closed の対処方法

クエリ(SQL文)実行結果のコールバック内で更に別のクエリを実行時に次のようなエラーが発生することがあります。

[Error: SQLITE_MISUSE: Database handle is closed] {
  errno: 21,
  code: 'SQLITE_MISUSE'
}

これはdb.close()が先に動作するためです。 db.close()以前に発行済みのクエリは実行されてからデータベースのクローズが行われますが、コールバック内のクエリは未だ発行されていないためエラーが発生します。 これを回避するためには、コールバック内のクエリを実行してから、db.close()をコールするようにします。

このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

コメント

メールアドレスが公開されることはありません。 が付いている欄は必須項目です