How to convert PostgreSQL 9.4's jsonb type to float

前端 未结 7 635
误落风尘
误落风尘 2020-12-14 14:36

I\'m trying the following query:

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

(The +1.0 is just there

相关标签:
7条回答
  • 2020-12-14 14:47

    Now we can do it!

    In nowadays we can cast directly from JSONb to SQL datatypes. I am using PostgreSQL v12.3, where it is working fine:

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

    Sub-questions:

    • From which version is it possible?

    • It is a syntax sugar or a real conversion?

    • If real "binary JSONb → binary SQL" conversion, where the micro-optimizations?
      For example, what wold be faster (?) tham "binary JSONb → string → binary SQL"? boolean→boolean, number→numeric, number→int, number→bigint; number→flloat, number→double.

    • Why not optimized for NULL?
      Curiosily the "NULL to SqlType" not works, "ERROR: cannot cast jsonb null to type integer".


    Benchmark suggestion

    How to check? When PostgreSQL optimize loop queries?

    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;
    
    0 讨论(0)
  • 2020-12-14 14:48

    You must to cast the json value to text and then to float.

    Try this:

    (json_data #>> '{field}')::float
    
    0 讨论(0)
  • 2020-12-14 14:51

    There are two operations to get value from JSON. The first one -> will return JSON. The second one ->> will return text.

    Details: JSON Functions and Operators

    Try

    SELECT (json_data->'position'->>'lat')::float + 1.0 AS lat
    FROM updates
    LIMIT 5
    
    0 讨论(0)
  • 2020-12-14 15:04

    Per documentation, there are also the functions

    jsonb_populate_record()
    jsonb_populate_recordset()
    

    Analog to their json twins (present since pg 9.3)

    json_populate_record()
    json_populate_recordset()
    

    You need a predefined row type. Either use the row-type of an existing table or define one with CREATE TYPE. Or substitute with a temporary table ad hoc:

    CREATE TEMP TABLE x(lat float);

    Can be a single column or a long list of columns.

    Only those columns are filled, where the name matches a key in the json object. The value is coerced to the column type and has to be compatible or an exception is raised. Other keys are ignored.

    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;
    

    Using an implicit LATERAL JOIN here.

    Similarly, use jsonb_populate_recordset() to decompose arrays into multiple rows per entry.

    This works the same way in Postgres 9.3 with json. There is the added benefit that casting to / from text internally is not necessary for numeric data in jsonb.

    0 讨论(0)
  • 2020-12-14 15:05

    When creating a view I used 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;
    
    0 讨论(0)
  • 2020-12-14 15:11

    AFAIK there's no json->float casting in Postgres, so you could try an explicit (json_data->'position'->'lat')::text::float cast

    0 讨论(0)
提交回复
热议问题