101

次のようなクエリを実行しようとしています。

SELECT * FROM table WHERE id IN (1,2,3,4)

問題は、フィルター処理する ID のリストが一定ではなく、実行ごとに異なる必要があることです。ソースの信頼性に関係なく、実際にはクエリに含まれるすべてのものをエスケープしますが、信頼できないソースからのものである可能性があるため、ID もエスケープする必要があります。

node-postgres は、バインドされたパラメーターでのみ機能するようです: client.query('SELECT * FROM table WHERE id = $1', [ id ]); これは、既知の数の値 ( ) があれば機能しますが、配列パラメーターの特別な処理がないように見えるためclient.query('SELECT * FROM table WHERE id IN ($1, $2, $3)', [ id1, id2, id3 ])、配列を直接操作することはできません。client.query('SELECT * FROM table WHERE id IN ($1)', [ arrayOfIds ])

配列内のアイテムの数に応じてクエリ テンプレートを動的に構築し、ids 配列をクエリ パラメーター配列 (私の実際のケースでは、id のリスト以外のパラメーターも含まれています) に拡張することは、不当に負担がかかるようです。node-postgres は値のエスケープ メソッドを提供しないため、クエリ テンプレートで ID のリストをハードコーディングすることも実行可能ではないようです。

これは非常に一般的な使用例のように思われるので、実際には何かを見落としていると思いますがIN (values)、node-postgres で一般的な SQL 演算子を使用できないというわけではありません。

私が上に挙げた方法よりも洗練された方法でこの問題を解決した人がいる場合、または node-postgres について本当に何かが足りない場合は、助けてください。

4

7 に答える 7

127

@ebohlman's answerへのコメントに基づいて、あなたは近かったようです。使用できますWHERE id = ANY($1::int[])。PostgreSQL は、配列を、パラメータが in にキャストされる型に変換$1::int[]します。だからここに私のために働く不自然な例があります:

var ids = [1,3,4]; 

var q = client.query('SELECT Id FROM MyTable WHERE Id = ANY($1::int[])',[ids]);

q.on('row', function(row) {
  console.log(row);
})

// outputs: { id: 1 }
//          { id: 3 }
//          { id: 4 }
于 2012-05-31T08:15:24.633 に答える
66

この質問は以前に github の問題リストで見たことがあります。正しい方法は、配列に基づいてパラメーターのリストを動的に生成することです。このようなもの:

var arr = [1, 2, "hello"];
var params = [];
for(var i = 1; i <= arr.length; i++) {
  params.push('$' + i);
}
var queryText = 'SELECT id FROM my_table WHERE something IN (' + params.join(',') + ')';
client.query(queryText, arr, function(err, cb) {
 ...
});

そうすれば、postgres のパラメーター化されたエスケープを取得できます。

于 2012-07-27T16:10:58.173 に答える
32

私が見つけた最善の解決策は、ANY関数を Postgres の配列強制で使用することでした。これにより、列を任意の値の配列と一致させることができますcol IN (v1, v2, v3)。これはpero's answerのアプローチですが、ここでは のパフォーマンスがANYと同じであることを示していINます。

クエリ

クエリは次のようになります。

SELECT * FROM table WHERE id = ANY($1::int[])

最後のビットは$1::int[]、「id」列のタイプに合わせて変更できます。たとえば、ID のタイプが の場合、引数を UUID の配列に強制するようにuuid記述します。Postgres データ型のリストについては、こちらを参照してください$1::uuid[]

これは、クエリ文字列を作成するコードを記述するよりも簡単で、SQL インジェクションに対して安全です。

node-postgres を使用すると、完全な JavaScript の例は次のようになります。

var pg = require('pg');

var client = new pg.Client('postgres://username:password@localhost/database');
client.connect(function(err) {
  if (err) {
    throw err;
  }

  var ids = [23, 65, 73, 99, 102];
  client.query(
    'SELECT * FROM table WHERE id = ANY($1::int[])',
    [ids],  // array of query arguments
    function(err, result) {
      console.log(result.rows);
    }
  );
});

パフォーマンス

SQL クエリのパフォーマンスを理解する最良の方法の 1 つは、データベースがクエリを処理する方法を調べることです。サンプル テーブルには、約 400 行と、タイプ の「id」という主キーがありtextます。

EXPLAIN SELECT * FROM tests WHERE id = ANY('{"test-a", "test-b"}');
EXPLAIN SELECT * FROM tests WHERE id IN ('test-a', 'test-b');

どちらの場合も、Postgres は同じクエリ プランを報告しました。

Bitmap Heap Scan on tests  (cost=8.56..14.03 rows=2 width=79)
  Recheck Cond: (id = ANY ('{test-a,test-b}'::text[]))
  ->  Bitmap Index Scan on tests_pkey  (cost=0.00..8.56 rows=2 width=0)
        Index Cond: (id = ANY ('{test-a,test-b}'::text[]))

テーブルのサイズ、インデックスがある場所、およびクエリに応じて、異なるクエリ プランが表示される場合があります。ただし、上記のようなクエリの場合は、同じ方法で処理されますANYIN

于 2014-12-30T23:19:45.940 に答える
19

pg-promiseを使用すると、これはCSV フィルター(カンマ区切り値)を介してうまく機能します。

const values = [1, 2, 3, 4];

db.any('SELECT * FROM table WHERE id IN ($1:csv)', [values])
    .then(data => {
        console.log(data);
    })
    .catch(error => {
        console.log(error);
    });

また、さまざまなデータ型に関する懸念に対処するために、:csvModifier は配列を csv にシリアル化し、すべての値を JavaScript の型に応じて適切な PostgreSQL 形式に変換し、さらにCustom Type Formattingをサポートします。

また、次のような混合型の値がある場合: const values = [1, 'two', null, true]、正しくエスケープされた SQL を取得します。

SELECT * FROM table WHERE id IN (1, 'two', null, true)

アップデート

v7.5.1 から、pg-promiseはフィルター:listの交換可能なエイリアスとしてサポートを開始しました。:csv

db.any('SELECT * FROM table WHERE id IN ($1:list)', [values])
于 2015-04-11T08:52:58.043 に答える
0

別の可能な解決策は、次のUNNESTように関数を使用することです。

 var ids = [23, 65, 73, 99, 102];
 var strs = ['bar', 'tar', 'far']
 client.query(
   'SELECT * FROM table WHERE id IN(SELECT(UNNEST($1))',
    [ids],  // array of query arguments
    function(err, result) {
       console.log(result.rows);
    }
);
client.query(
   'SELECT * FROM table WHERE id IN(SELECT(UNNEST($1))',
    [strs],  // array of query arguments
    function(err, result) {
       console.log(result.rows);
    }
);

これをストアド プロシージャで使用しましたが、正常に動作します。node-pg コードからも動作するはずです。

UNNEST 関数については、こちらを参照してください。

于 2015-03-26T12:03:57.417 に答える
-1

アイデアは一般的に:

var invals = [1,2,3,4], cols = [...fields];
var setvs = vs => vs.map(v=> '$'+ (values.push(v))  ).join();

var values = [];
var text = 'SELECT '+ setvs(cols) +' FROM table WHERE id IN (' + setvs(invals) +')';
于 2018-11-30T22:55:12.147 に答える