使用node和pg-promise加入postgres中的值列表

问题描述 投票:1回答:2

我正在尝试创建一个查询,如

SELECT e.col1, e.col2 
FROM entity e
INNER JOIN (
    VALUES
    (1377776),(1377792),(1377793),(1377794),(1377795),(1377796)
) ex(ex_entityid) ON (entityid = ex_entityid)

鉴于我有一个包含数组中的数字13777xx的数组,我将如何生成此查询?

我从这个问题得到了这个语法:https://stackoverflow.com/a/17824797/425544。我的输入列表足够大,使用IN太慢了。

到目前为止,使用$ 0:csv,我可以将我的值设为逗号分隔列表。我不知道如何格式化值,使其周围有括号。如果我给出没有:csv标记的数组,它会在值之前添加“array”,然后我得到语法错误。

node.js postgresql pg-promise
2个回答
1
投票

鉴于我有一个包含数组中的数字13777xx的数组,我将如何生成此查询?

Arbitrary numbers

如果你有一个实际的数组,只需传递数组文字,形式为:

'{1377776,1377792,1377793}'

对于只有一个满手值的小型数组,您可以在连接中使用ANY构造:

SELECT col1, col2 
FROM   entity
WHERE  entityid = ANY ($my_array::int[]);

对于字符串文字,您需要显示一个显式类型转换。

对于长数组,将数组排除到集合(派生表)然后加入like mu commented会更有效:

SELECT col1, col2
FROM   unnest(my_array::int[]) ex(entityid)
JOIN   entity USING (entityid);

通过匹配的未列出数字列名,您可以方便地使用短USING子句作为连接条件。

请注意一个细微的差别:第一个查询隐式折叠输入中的重复项,而第二个查询使用连接为输入中的重复项生成重复项。你的选择。

或者,您也可以将单个值传递给IN表达式。但这通常较慢。 (再次:折叠重复。)喜欢:

...
WHERE  entityid IN (1377776, 1377792, 1377793);

看到:

对于重复操作,您可以创建VARIADIC函数并将单个数字作为参数传递(或者根据您的选择将单个数组文字传递)。看到:

Not so arbitrary numbers

如果您真的想根据“数字13777xx”(即1377700和1377799之间的所有数字)查询,请使用generate_series()。喜欢:

SELECT col1, col2 
FROM   generate_series(1377700, 1377799) entityid
JOIN   entity USING (entityid);

或者,最简单,最快速,使用单一范围谓词调整WHERE子句:

SELECT col1, col2 
FROM   entity
WHERE  entityid BETWEEN 1377700 AND 1377799;

1
投票

这是一种非标准格式,因此您需要使用Custom Type Formatting

const wrap = arr => ({
    rawType: true,
    toPostgres: () => arr.map(a => pgp.as.format('($1)', [a])).join()
});

现在您可以使用这样的包装数组作为简单的格式化变量:

const data = [1377776, 1377792, 1377793];
db.any('... INNER JOIN (VALUES $1)', [wrap(data)]);
© www.soinside.com 2019 - 2024. All rights reserved.