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

joining against a value list in postgres using node and pg-promise

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

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 的数组,我将如何生成此查询?

我从这个问题中得到了这个语法:。我的输入列表足够大,使用 IN 太慢了。

到目前为止,使用 $0:csv,我可以将我的值设为逗号分隔列表。我不知道如何格式化这些值,以便它有括号。如果我给出不带 :csv 标签的数组,它会在值之前添加 "array",然后出现语法错误。

Given I have an array containing the numbers 13777xx in an array, how would I generate this query?

任意数

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

'{1377776,1377792,1377793}'

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

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

对于字符串文字,您将需要一个显式类型转换,如所演示的那样。

对于长数组,将数组解除嵌套到一个集合(派生table)然后加入:

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

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

注意一个细微的差别:第一个查询隐含地折叠输入中的重复项,而第二个查询为输入中的重复项生成重复项。您的选择。

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

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

参见:

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

  • Pass multiple values in single parameter
  • Return rows matching elements of input array in plpgsql function

不是那么随意的数字

如果您确实想根据 “数字 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;

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

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

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

const data = [1377776, 1377792, 1377793];
db.any('... INNER JOIN (VALUES )', [wrap(data)]);