狛ログ

2018年6月25日月曜日

knexライブラリのIN句でプレースホルダを使うときの注意点


オフィス狛 技術部のHammarです。

node.js、Postgresqlという開発環境で、knexというSQLライブラリを利用して開発をしているのですが、今回はIN句でプレースホルダを使って配列をセットしてクエリを作成した時にハマったことを書いてみようと思います。

通常knexライブラリでIN句を使ってクエリを作成するとこんな感じになると思います。
    knex
        .select('name')
        .from('users')
        .whereIn('id', [1, 2, 3]);
■出力SQL
    select `name` from `users` where `id` in (1, 2, 3);

そして上記を応用してIN句にプレースホルダを使うとするとこのような感じになります。
    knex
        .select('name')
        .from('users')
        .whereRaw('id IN (?, ?, ?)', [1, 2, 3]);
■出力SQL
    select `name` from `users` where `id` in (1, 2, 3);

で、実際のプログラムではこのIN句の中を配列の変数で扱ってクエリを作ることが多いと思いますが、その場合はこんな感じになると思います。
    const array = [1, 2, 3];

    knex
        .select('name')
        .from('users')
        .whereRaw('id in (?)', [array]);

このクエリでも基本的に問題なく動きますが、このクエリだと配列の中の値をすべて文字列として認識してしまい、数値項目に対してこのクエリを実行するとsyntaxエラーとなってしまうんです。
上記のクエリの場合、idというカラムがint型の場合は下記のようなクエリがながれてしまい値が取れません。
■出力SQL
    select `name` from `users` where `id` in ("1", "2", "3");

いろいろと調べてみてようやくたどり着いたのが、プレースホルダを??にするという対応でした。
https://github.com/tgriesser/knex/issues/1537

でこんな感じになります。単純に?を2つにしただけ。
    const array = [1, 2, 3];

    knex
        .select('name')
        .from('users')
        .whereRaw('id in (??)', [array]);
■出力SQL
    select `name` from `users` where `id` in (1, 2, 3);

これで意図する値の取得ができるようになりました。

この事象はpostgresqlだけ?なのか、ほかのmysql等のRDBではどうなのかはわかりませんが、posgresqlでknexライブラリを使う際には上記を参考にしてみてください。

0 件のコメント:

コメントを投稿