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

时间:2014-07-18 13:37:53

标签: sql postgresql casting jsonb postgresql-9.4

我正在尝试以下查询:

SELECT (json_data->'position'->'lat') + 1.0 AS lat FROM updates LIMIT 5;

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

我收到错误:

ERROR:  operator does not exist: jsonb + numeric

如果我添加显式转换:

SELECT (json_data->'position'->'lat')::float + 1.0 AS lat FROM updates LIMIT 5;

错误变为:

ERROR:  operator does not exist: jsonb + double precesion

据我所知,大多数jsonb值都不能转换为浮点值,但在这种情况下,我知道这些值都是JSON数。

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

7 个答案:

答案 0 :(得分:73)

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

详细信息:JSON Functions and Operators

尝试

SELECT (json_data->'position'->>'lat')::float + 1.0 AS lat
FROM updates
LIMIT 5

答案 1 :(得分:6)

Per documentation,还有函数

jsonb_populate_record()
jsonb_populate_recordset()

模拟他们的json双胞胎(自第9.3页开始)

json_populate_record()
json_populate_recordset()

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

CREATE TEMP TABLE x(lat float);

可以是单列或长列列。

仅填充这些列,其中名称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;

在这里使用implicit LATERAL JOIN

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

这与使用json的Postgres 9.3中的工作方式相同。 text中的数字数据不需要内部投放到jsonb内部的额外好处。

答案 2 :(得分:4)

AFAIK在Postgres中没有json->浮动播放,所以你可以尝试一个明确的(json_data->'position'->'lat')::text::float强制转换

答案 3 :(得分:3)

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

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

(json_data #>> '{field}')::float

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

json_data #>> '{field}'::float

这是我在代码中犯的错误,花了我一段时间才能看到它-一旦发现,就可以轻松解决。

答案 4 :(得分:1)

您必须将json值转换为text,然后再浮动。

试试这个:

config.Routes.MapHttpRoute(
    name: "GetAllRoute",
    routeTemplate: "api/{controller}.{ext}"/*,
    defaults: new { action = "Get" }*/ // this was causing the issue
);

答案 5 :(得分:0)

创建视图时,我使用了CAST:

create view mydb.myview as
            select id,
            config->>'version' as version,
            config->>'state' as state,
            config->>'name' as name,
            config->>'internal-name' as internal_name,
            config->>'namespace' as namespace,         
            create_date,
            update_date,
            CAST(config ->> 'version' as double precision) as version_number
            from mydb.mytbl;

答案 6 :(得分:0)

现在我们可以做到!

如今,我们可以直接从JSONb转换为SQL数据类型。我使用的是PostgreSQL v12.3 ,在这里运行良好:

SELECT (j->'i')::int, (j->>'i')::int, (j->'f')::float, (j->>'f')::float
FROM  (SELECT '{"i":123,"f":12.34}'::jsonb) t(j); 

子问题:

  • 可以从哪个版本开始?

  • 它是语法糖还是real conversion

  • 如果是真正的“二进制JSONb→二进制SQL”转换,则在哪里进行微优化?
    例如,请问“二进制JSONb→字符串”更快吗? →二进制SQL”?布尔值→布尔值,数字→数字,数字→int,数字→bigint;数字→浮动,数字→双。

  • 为什么不针对NULL优化?
    奇怪的是,“将NULL转换为SqlType”无效,“错误:无法将jsonb null强制转换为整数”。


基准建议

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

EXPLAIN ANALYSE SELECT (j->'i')::int, (j->'f')::float       -- bynary to bynary INT and FLOAT
-- EXPLAIN ANALYSE SELECT (j->>'i')::int, (j->>'f')::float  -- string to bynary INT and FLOAT

-- EXPLAIN ANALYSE SELECT (j->'i')::numeric, (j->'f')::numeric    -- bynary to bynary NUMERIC
-- EXPLAIN ANALYSE SELECT (j->>'i')::numeric, (j->>'f')::numeric  -- string to bynary NUMERIC

FROM (
  SELECT (('{"i":'||x||',"f":'||x||'.34}')::jsonb) as j FROM  generate_series(1,599999) g(x)
  -- SELECT (('{"i":123,"f":12.34}')::jsonb) as j FROM  generate_series(1,599999) g(x)
) t;