使用 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_at
是 timestamptz
类型(可能应该是这样),current_date
会引入对会话时区设置的依赖,这是一个偷偷摸摸的、不必要的来源corner-case 个错误。参见:
- PostgreSQL date() with timezone
而且“名字”不是一个好名字。
我针对 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_at
是 timestamptz
类型(可能应该是这样),current_date
会引入对会话时区设置的依赖,这是一个偷偷摸摸的、不必要的来源corner-case 个错误。参见:
- PostgreSQL date() with timezone
而且“名字”不是一个好名字。