使用 PostgreSQL / json 执行除法

Performing division with PostgreSQL / json

我针对 Postgres 数据库中的 table 编写了一个简单的查询,该数据库包含 json 类型的列“清单”。每个单元格都包含一个很长的值,我正在提取“大小”的数值。

我需要创建一个新列(也许称之为“以 MB 为单位的大小”),然后对大小进行除法。具体来说,我需要将 size 的值除以 1024,两次。我已经尝试了所有我能找到的例子都无济于事。

这是我当前的查询,以及一小部分结果:

select customers.name, images.customer_id, images.captured_at, images.name,
 manifest -> 'size' as image_size
from public.images
inner join public.customers on customers.id = images.customer_id
where (captured_at > current_date - interval '12 months')
order BY captured_at desc
Name       customer_id   captured_at   name         image_size
Acme Inc   12345         2022-05-31    Central HMA  628032520  

目标是取 image_size,除以 1024 两次,并将结果存储在名为“size in MB”的新列中。所以在这种情况下,数学的结果将是 598。

要提取标量值(不是另一个 json),请使用 ->> operator(不是 ->)。
即 returns 输入 text。因此,在对数字进行数学运算之前,您还需要 cast:

(manifest ->> 'size')::bigint  -- or numeric? see below!

参见:

  • Postgres data type cast

可以integer division截断,计算598你预计:

SELECT 628032520 / 1024 / 1024  -- 598  -- truncated!

转换为浮点数或 numeric 可避免整数除法并显示您的样本值更接近 599:

SELECT 628032520.0 / 2^20  -- 598.9384841918945313  -- precise

numeric constant 123 解析为类型 integer,而 123.0(包含点 .)解析为 numeric
并且 1024 * 1024 = 1048576 = 2^20.

也许是圆的?还是保留两位小数?

SELECT round(628032520.0 / 2^20)     -- 599    -- rounded
     , round(628032520.0 / 2^20, 2)  -- 599.94

但是 考虑 built-in 函数 pg_size_pretty() 而不是为了这个目的而制作的:

SELECT pg_size_pretty(628032520.0)  -- 599 MB  -- formatted text
     , pg_size_pretty(232520.0)     -- 227 kB

所以:

SELECT c.name AS customer, i.customer_id, i.captured_at, i.name AS image
     , pg_size_pretty((c.manifest ->> 'size')::numeric) AS image_size
FROM   public.images i
JOIN   public.customers c ON c.id = i.customer_id
WHERE  captured_at > date_trunc('day', now()) - interval '12 months'
ORDER  BY captured_at DESC;

应该给你:

customer   customer_id   captured_at   image        image_size
Acme Inc   12345         2022-05-31    Central HMA  599 MB  

我还解决了您查询的其他几个问题。

假设 captured_attimestamptz 类型(可能应该是这样),current_date 会引入对会话时区设置的依赖,这是一个偷偷摸摸的、不必要的来源corner-case 个错误。参见:

  • PostgreSQL date() with timezone

而且“名字”不是一个好名字。