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'
対処方法
- \node_modules\sqlite3\lib\binding\napi-v6-win32-unknown-x64ディレクトリをカレントディレクトリにコピーする
- \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()
をコールするようにします。