【问题标题】:joining against a value list in postgres using node and pg-promise使用 node 和 pg-promise 加入 postgres 中的值列表
【发布时间】:2019-04-05 20:52:21
【问题描述】:

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

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 标记的数组,它会在值前添加“数组”,然后出现语法错误。

【问题讨论】:

    标签: node.js postgresql pg-promise


    【解决方案1】:

    假设我有一个包含数字 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;
    

    【讨论】:

    • 我用的是unnest。谢谢!
    • @Nikhil 奇怪的是,作为 pg-promise 的作者,我给了你问题的准确答案,但你接受的答案离它还有一步之遥吗? :)
    【解决方案2】:

    这是一种非标准格式,所以你需要使用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)]);
    

    【讨论】:

      猜你喜欢
      • 2017-03-05
      • 2018-01-07
      • 1970-01-01
      • 2016-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-20
      • 2016-05-01
      相关资源
      最近更新 更多