如何将PostgreSQL 9.4的jsonb类型转换为float

fad*_*bee 33 sql postgresql casting jsonb postgresql-9.4

我正在尝试以下查询:

SELECT (json_data->'position'->'lat') + 1.0 AS lat FROM updates LIMIT 5;
Run Code Online (Sandbox Code Playgroud)

(+ 1.0只是强制转换为浮点数.我的实际查询要复杂得多,这个查询只是问题的一个测试用例.)

我收到错误:

ERROR:  operator does not exist: jsonb + numeric
Run Code Online (Sandbox Code Playgroud)

如果我添加显式转换:

SELECT (json_data->'position'->'lat')::float + 1.0 AS lat FROM updates LIMIT 5;
Run Code Online (Sandbox Code Playgroud)

错误变成:

ERROR:  operator does not exist: jsonb + double precesion
Run Code Online (Sandbox Code Playgroud)

我知道大多数jsonb值都不能转换成浮点数,但在这种情况下我知道lats都是JSON数.

是否有一个函数将jsonb值转换为浮点数(或为uncastable返回NULL)?

Igo*_*nko 84

有两种操作可以从中获取价值JSON.第一个->将返回JSON.第二个->>将返回文本.

详细信息:JSON函数和运算符

尝试

SELECT (json_data->'position'->>'lat')::float + 1.0 AS lat
FROM updates
LIMIT 5
Run Code Online (Sandbox Code Playgroud)

  • 可能你不想乱用值所以使用:: float + 0.0 AS lat,1 lat变化是非常大的差异!! (2认同)
  • 为什么我需要添加 0.0(或者在你的情况下添加 1.0),它不是已经使用 ::float 类型转换为浮点数了吗? (2认同)

Pet*_*uss 12

现在我们可以做到了!

\n

现在我们可以直接从 JSONb 转换为 SQL 数据类型。我正在使用 PostgreSQL v12.3,它工作正常:

\n
SELECT (j->\'i\')::int, (j->>\'i\')::int, (j->\'f\')::float, (j->>\'f\')::float\nFROM  (SELECT \'{"i":123,"f":12.34}\'::jsonb) t(j); \n
Run Code Online (Sandbox Code Playgroud)\n
\n

子问题:

\n
    \n
  • 从哪个版本可以?

    \n
  • \n
  • 它是语法糖还是真正的转换

    \n
  • \n
  • 如果真正的“二进制JSONb\xe2\x86\x92二进制SQL”转换,微优化在哪里?
    例如,什么会比“二进制 JSONb \xe2\x86\x92 字符串 \xe2\x86\x92 二进制 SQL”更快(?)?布尔\xe2\x86\x92布尔值,数字\xe2\x86\x92数字,数字\xe2\x86\x92int,数字\xe2\x86\x92bigint;数字\xe2\x86\x92float,数字\xe2\x86\x92double。

    \n
  • \n
  • 为什么不针对 NULL 进行优化?
    奇怪的是,“NULL 到 SqlType”不起作用,“错误:无法将 jsonb null 转换为整数类型”。

    \n
  • \n
\n
\n

基准建议

\n

如何检查?PostgreSQL何时优化循环查询?

\n
EXPLAIN ANALYSE SELECT (j->\'i\')::int, (j->\'f\')::float       -- bynary to bynary INT and FLOAT\n-- EXPLAIN ANALYSE SELECT (j->>\'i\')::int, (j->>\'f\')::float  -- string to bynary INT and FLOAT\n\n-- EXPLAIN ANALYSE SELECT (j->\'i\')::numeric, (j->\'f\')::numeric    -- bynary to bynary NUMERIC\n-- EXPLAIN ANALYSE SELECT (j->>\'i\')::numeric, (j->>\'f\')::numeric  -- string to bynary NUMERIC\n\nFROM (\n  SELECT ((\'{"i":\'||x||\',"f":\'||x||\'.34}\')::jsonb) as j FROM  generate_series(1,599999) g(x)\n  -- SELECT ((\'{"i":123,"f":12.34}\')::jsonb) as j FROM  generate_series(1,599999) g(x)\n) t;\n
Run Code Online (Sandbox Code Playgroud)\n
\n

PostgreSQL 错误?

\n

即使是现在,2021 年版本 pg13 版本...不强制转换 NULL 是没有意义的:自然是强制转换NULL::int为整数,但 PostgreSQL 在自动强制转换中失败:

\n
SELECT (j->\'i\')::int FROM  (SELECT \'{"i":null}\'::jsonb) t(j); -- fail\n
Run Code Online (Sandbox Code Playgroud)\n

结果是“错误:无法将 jsonb null 转换为整数类型”

\n


kni*_*tti 6

AFAIK有Postgres里没有json->浮铸造,所以你可以尝试一个明确的(json_data->'position'->'lat')::text::float


Erw*_*ter 6

根据文档,还有功能

jsonb_populate_record()
jsonb_populate_recordset()
Run Code Online (Sandbox Code Playgroud)

与他们的json双胞胎类比(自第9.3页开始)

json_populate_record()
json_populate_recordset()
Run Code Online (Sandbox Code Playgroud)

您需要预定义的行类型.使用现有表的行类型或使用CREATE TYPE.或者用临时表替换:

CREATE TEMP TABLE x(lat float);
Run Code Online (Sandbox Code Playgroud)

可以是单列或长列列.

只有那些中填入,其中名字一个匹配关键json对象.该被强制转换为列类型,并且必须兼容或引发异常.其他键被忽略.

SELECT lat + 1  -- no need for 1.0, this is float already
FROM   updates u
     , jsonb_populate_record(NULL::x, u.json_data->'position')
LIMIT  5;
Run Code Online (Sandbox Code Playgroud)

在这里使用隐含LATERAL JOIN.

同样,使用jsonb_populate_recordset()每个条目将数组分解为多行.

这在Postgres 9.3中的工作方式与此相同json.还有一个额外的好处,text就是数字数据不需要内部进/出内部jsonb.


roc*_*ady 5

添加说明,因为这是“JSONB 浮点转换”搜索的热门搜索 - 请注意,您需要将 JSON 转换括在方括号中,然后应用“::”转换。

如上所述,正确的方法是:

(json_data #>> '{field}')::float
Run Code Online (Sandbox Code Playgroud)

相反,如果您尝试这样做,它将失败:

json_data #>> '{field}'::float
Run Code Online (Sandbox Code Playgroud)

这是我在代码中犯的错误,我花了一段时间才看到它 - 一旦我注意到就很容易修复。