sqlite3 の SQL で名前付きパラメーターを使うには

SQL で値をバインドするとき、よく見るかける例ではプレースホルダーを ? にしていますが、名前付きパラメーターで記述した方が可読性も良く、その後のメンテナンスも楽です。

環境

  • SQLite Version 3.32.3
  • Node.js Version 16.3.0
  • sqlite3 Version 5.0.2

名前付きパラメーターを使ったとき

SQL の記述で、パラメーターで渡したい値に $ で始まる変数名を使い、その名前で値をバインドします。

const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database(':memory:');
const sql = `
INSERT INTO users(id, name, email, address)
VALUES($id, $name, $email, $address)
ON CONFLICT(id)
DO UPDATE SET
  name = $name,
  email = $email,
  address = $address
;`;
db.serialize(function () {
  const stmt = db.prepare(sql);
  const params = {
    $id: 'kuma',
    $name: 'kuma emon',
    $email: 'master@kuma-emon.com',
    $address: 'kuma 1-2-3',
  };
  stmt.run(params);
  stmt.finalize();
});
db.close();

$ と : と @ を使うことができますが、公式は $ を勧めています。

Named parameters can be prefixed with :name@name and $name. We recommend using $name since JavaScript allows using the dollar sign as a variable name without having to escape it. 

https://github.com/mapbox/node-sqlite3/wiki/API#databaserunsql-param–callback

名前付きパラメーターを使わなかったとき

プレースホルダーを ? で記述したときは、次のようになります。

const sqlite3 = require('sqlite3').verbose();
const db = new sqlite3.Database(':memory:');
const sql = `
INSERT INTO users(id, name, email, address)
VALUES(?, ?, ?, ?)
ON CONFLICT(id)
DO UPDATE SET
  name = ?,
  email = ?,
  address = ?
;`;
db.serialize(function () {
  const stmt = db.prepare(sql);
  const params = [
    'kuma',
    'kuma emon',
    'master@kuma-emon.com',
    'kuma 1-2-3',
    'kuma emon',
    'master@kuma-emon.com',
    'kuma 1-2-3',
  ];
  stmt.run(params);
  stmt.finalize();
});
db.close();

名前付きパラメーターの良さが分かる

SQL文と渡すパラメーターを比較すると、名前付きパラメーターの良さが分かります。

  // 名前付きパラメーター
  // INSERT INTO users(id, name, email, address)
  // VALUES($id, $name, $email, $address)
  // ON CONFLICT(id)
  // DO UPDATE SET
  //   name = $name,
  //   email = $email,
  //   address = $address;
  const params = {
    $id: 'kuma',
    $name: 'kuma emon',
    $email: 'master@kuma-emon.com',
    $address: 'kuma 1-2-3',
  };

  // 名前付きパラメーターでない
  // INSERT INTO users(id, name, email, address)
  // VALUES(?, ?, ?, ?)
  // ON CONFLICT(id)
  // DO UPDATE SET
  //   name = ?,
  //   email = ?,
  //   address = ?;
  const params = [
    'kuma',
    'kuma emon',
    'master@kuma-emon.com',
    'kuma 1-2-3',
    'kuma emon',
    'master@kuma-emon.com',
    'kuma 1-2-3',
  ];

名前付きパラメーターを使わなかった場合、プレースホルダーの順に値を渡すようになり、

  • 順番通りに値を渡す必要がある
    → パラメーターが増減するような変更が SQL にあったときに注意が必要
  • 同じ変数も、現れる順番に渡す必要がある
    → INSERT と UPDATE で同じ変数なのに、それぞれで指定が必要

というように名前付きパラメーターの方が、可読性とメンテナンスの面で優れています。

コメント