【问题标题】:PostgreSQL query to iterate through array and perform product calculation on each cellPostgreSQL 查询遍历数组并对每个单元格执行乘积计算
【发布时间】:2021-08-16 20:47:22
【问题描述】:

我有一个包含整数数组的单元格(使用语法创建的列:some_arrays integer[]

    | id |   some_arrays   |
    |----+-----------------|
    | 0  |  10, 15, 20, 25 |
    |----+-----------------|
    | 1  |  1, 3, 5, 7     |
    |----+-----------------|
    | 2  |  33, 674, 2, 4  |
    |----+-----------------|

对于任何给定的行,我想遍历每个数组,并为每个元素返回数组中除自身之外的所有元素的乘积。

例如:

some_arrays[0]
  -> [10, 15, 20, 25]
  -> [15 * 20 * 25, 10 * 20 * 25, 10 * 15 * 25, 10 * 15 * 20]
  -> [7500, 5000, 3750, 3000]

在 Python 中,我们可以这样做:

def get_prod(array, n):
    prod = 1
    # calculate prod all elements in array
    for i in range(n):
        prod *= array[i]
    # replace each element by the product divided by that element
    for i in range(n):
        array[i] = prod // array[i]

array = [10, 15, 20, 25]
n = len(array)
get_prod(array, n)
for i in range(n):
    print(array[i], end=" ")

在 postgreSQL 中,选择一个单元格、遍历每个元素并获得其他元素的乘积的正确查询是什么?

可以将每个单元格的每个元素加倍并将其显示到新列:

SELECT id, (SELECT SUM(a) FROM unnest(some_arrays) AS a) AS total FROM this_table;
SELECT some_arrays,
  ARRAY(SELECT x * 2
        FROM unnest(some_arrays) AS x) AS doubles
FROM table;

这会产生:

|   some_arrays   |   doubled       | 
|-----------------+-----------------
|  10, 15, 20, 25 |  20, 30, 40, 50 | 
|-----------------+-----------------| 
|  1, 3, 5, 7     |  2, 6, 10, 14   | 
|-----------------+-----------------| 
|  66, 674, 2, 4  |  33, 1348, 4, 8 | 
|-----------------+-----------------| 

(使用 Postgres 11.10)

感谢您提供有关编写综合 for 循环的任何提示!

【问题讨论】:

    标签: arrays postgresql filter


    【解决方案1】:

    显式循环是处理此任务的一种方法,但我更喜欢使用关系演算,

    postgresql 现在不知道如何做产品聚合,但你可以教它:

    create aggregate product(integer)
       (stype=bigint,sfunc=int84mul,initcond=1);
    

    这里的 int84mul 是一个内置函数,将一个 8 字节整数乘以一个 4 字节整数。它没有在文档中描述,但通过自省例如可见

    psql 命令\dfS+ *mul*

    然后

    select cell.*, product(a) 
    from cell, 
      lateral unnest(some_arrays) as a group by 1,2 order by 1;
    

    标识 |一些数组 |独家产品
    ----+---------------+------------ 0 | {10,15,20,25} | {7500,5000,3750,3000} 1 | {1,3,5,7} | {105,35,21,15} 2 | {33,674,2,4} | {5392,264,88968,44484}

    会给你结果:

     id |  some_arrays  | product 
    ----+---------------+---------
      0 | {10,15,20,25} |   75000
      1 | {1,3,5,7}     |     105
      2 | {33,674,2,4}  |  177936
    

    这很接近了。

    如果你将乘积除以单元格。

    with b as (
           select cell.*, product(a) 
           from cell,
              lateral unnest(some_arrays) as a group by 1,2 )
    select id,some_arrays, 
       ARRAY(SELECT product / x FROM unnest(some_arrays) AS x)
     AS exclusive_products from b order by 1;
    

    得到结果

     id |  some_arrays  |   exclusive_products   
    ----+---------------+------------------------
      0 | {10,15,20,25} | {7500,5000,3750,3000}
      1 | {1,3,5,7}     | {105,35,21,15}
      2 | {33,674,2,4}  | {5392,264,88968,44484}
    

    【讨论】:

    • 关于内置函数 int84mul 能说更多吗?例如,为什么这个乘法函数需要一个 8 字节或 4 字节整数? @贾森
    • 产品倾向于大数字,所以我选择了一个“bigint”来保存产品,常规整数是4个字节。
    • 还有其他几个乘法函数,这个函数被调整为将bigint 乘以integer postgresql 在计算算术表达式时在内部使用它。
    • 谢谢,了解查询背后发生了什么总是好的
    猜你喜欢
    • 2018-10-15
    • 2023-04-07
    • 2021-11-28
    • 2019-11-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-02
    • 1970-01-01
    • 2019-04-03
    相关资源
    最近更新 更多