我正在尝试创建一个查询,如
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”,然后我得到语法错误。
鉴于我有一个包含数组中的数字13777xx的数组,我将如何生成此查询?
如果你有一个实际的数组,只需传递数组文字,形式为:
'{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
函数并将单个数字作为参数传递(或者根据您的选择将单个数组文字传递)。看到:
如果您真的想根据“数字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('($1)', [a])).join()
});
现在您可以使用这样的包装数组作为简单的格式化变量:
const data = [1377776, 1377792, 1377793];
db.any('... INNER JOIN (VALUES $1)', [wrap(data)]);