web-dev-qa-db-fra.com

Comment convertir le type jsonb de PostgreSQL 9.4 en float

J'essaie la requête suivante:

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

(Le +1.0 est juste là pour forcer la conversion à flotter. Mes requêtes réelles sont beaucoup plus complexes, cette requête n'est qu'un test pour le problème.)

Je reçois l'erreur:

ERROR:  operator does not exist: jsonb + numeric

Si j'ajoute un casting explicite:

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

l'erreur devient:

ERROR:  operator does not exist: jsonb + double precesion

Je comprends que la plupart des valeurs jsonb ne peuvent pas être converties en flottants, mais dans ce cas, je sais que les lats sont tous des nombres JSON.

Existe-t-il une fonction qui convertit les valeurs jsonb en flottants (ou renvoie des valeurs NULL pour les non-castables)?

31
fadedbee

Il y a deux opérations pour obtenir la valeur de JSON. Le premier -> renverra JSON. Le deuxième ->> renverra du texte.

Détails: Fonctions et opérateurs JSON

Essayer

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

Par documentation , il y a aussi les fonctions

jsonb_populate_record()
jsonb_populate_recordset()

Analogique à leurs jumeaux Json (présents depuis la page 9.3)

json_populate_record()
json_populate_recordset()

Vous avez besoin d'un type de ligne prédéfini. Utilisez le type de ligne d'une table existante ou définissez-en un avec CREATE TYPE. Ou remplacez par une table temporaire ad hoc:

CREATE TEMP TABLE x(lat float);

Peut être une seule colonne ou une longue liste de colonnes.

Seules ces colonnes sont remplies, où le nom correspond à une clé dans le json objet. La valeur est contrainte au type de colonne et doit être compatible ou une exception est levée. Les autres clés sont ignorées.

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;

Utiliser un implicite LATERAL JOIN ici.

De même, utilisez jsonb_populate_recordset() pour décomposer les tableaux en plusieurs lignes par entrée.

Cela fonctionne de la même manière dans Postgres 9.3 avec json. Il y a l'avantage supplémentaire que la conversion vers/depuis text en interne n'est pas nécessaire pour les données numériques dans jsonb.

6
Erwin Brandstetter

AFAIK il n'y a pas de casting json-> float dans Postgres, vous pouvez donc essayer un cast explicite (json_data->'position'->'lat')::text::float

5
knitti

Ajout d'une clarification car cela apparaît comme le résultat le plus recherché pour une recherche de `` conversion flottante JSONB '' - notez que vous devez encapsuler la conversion JSON entre crochets, et alors appliquer le casting '::'.

Comme mentionné ci-dessus, la bonne méthode est:

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

Si vous essayez à la place, cela échouera:

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

C'était l'erreur que je faisais dans mon code et il m'a fallu un certain temps pour le voir - solution facile une fois que j'ai remarqué.

3
rocksteady

Vous devez transtyper la valeur json en texte puis flotter.

Essaye ça:

(json_data #>> '{field}')::float
1
Luis Castillo