lan*_*nzz 55 node.js node-postgres
我正在尝试执行这样的查询:
SELECT * FROM table WHERE id IN (1,2,3,4)
Run Code Online (Sandbox Code Playgroud)
问题是我要过滤的ID列表不是常量,每次执行时都需要不同.我还需要逃避id,因为它们可能来自不受信任的来源,尽管我实际上会逃避查询中的任何内容,无论源的可信度如何.
节点的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列表之外还包含其他参数)似乎是不合理的负担.在查询模板中对id列表进行硬编码似乎也不可行,因为node-postgres不提供任何值转义方法.
这似乎是一个非常常见的用例,所以我的猜测是我实际上忽略了某些东西,而不是不可能将常见的IN (values)SQL运算符与node-postgres一起使用.
如果有人以比我上面列出的方式更优雅的方式解决了这个问题,或者如果我真的错过了关于node-postgres的内容,请帮忙.
Per*_* P. 71
根据您对@ ebohlman的回答的评论,您可能已经接近了.你可以用WHERE id = ANY($1::int[]).PostgreSQL会将数组转换为参数转换为的类型$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 }
Run Code Online (Sandbox Code Playgroud)
小智 41
我们之前在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) {
...
});
Run Code Online (Sandbox Code Playgroud)
这样你就可以获得postgres参数化转义.
ide*_*ide 21
我发现的最好的解决方案是使用ANYPostgres的阵列强制功能.这使您可以将列与任意值的数组匹配,就像您已写出一样col IN (v1, v2, v3).这是pero答案中的方法,但在这里我表明它的表现ANY是相同的IN.
您的查询应如下所示:
SELECT * FROM table WHERE id = ANY($1::int[])
Run Code Online (Sandbox Code Playgroud)
最后说的那一点$1::int[]可以更改为与"id"列的类型相匹配.例如,如果您的ID类型是uuid,您将写入$1::uuid[]以强制参数为UUID数组.有关Postgres数据类型的列表,请参见此处.
这比编写代码来构造查询字符串更简单,并且可以安全地防止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);
}
);
});
Run Code Online (Sandbox Code Playgroud)
理解SQL查询性能的最佳方法之一是查看数据库如何处理它.示例表有大约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');
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,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[]))
Run Code Online (Sandbox Code Playgroud)
您可能会看到不同的查询计划,具体取决于表的大小,索引和查询.但对于像上面的查询,ANY并IN以相同的方式处理.
vit*_*y-t 16
使用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);
});
Run Code Online (Sandbox Code Playgroud)
为了解决对各种数据类型的关注,:csv修饰符将数组序列化为csv,同时根据其JavaScript类型将所有值转换为正确的PostgreSQL格式,甚至支持自定义类型格式.
如果您有这样的混合类型值:const values = [1, 'two', null, true],您仍将获得正确转义的SQL:
SELECT * FROM table WHERE id IN (1, 'two', null, true)
Run Code Online (Sandbox Code Playgroud)
UPDATE
从v7.5.1 开始,pg-promise开始支持过滤器:list的可互换别名:csv:
db.any('SELECT * FROM table WHERE id IN ($1:list)', [values])
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
30756 次 |
| 最近记录: |